diff --git a/lib/document.js b/lib/document.js index feffc4b..6032856 100644 --- a/lib/document.js +++ b/lib/document.js @@ -4,6 +4,7 @@ export default class DIDDocument { constructor( document, mode = 'reference' ) { this.id = document.id; + this.alsoKnownAs = document.alsoKnownAs; this.controller = document.controller; this.verificationMethod = document.verificationMethod; this.authentication = getRelationship( document.verificationMethod, document.authentication ); @@ -20,6 +21,7 @@ export default class DIDDocument { if( this.mode === 'explicit' ) return { id: this.id, + alsoKnownAs: this.alsoKnownAs, controller: this.controller, verificationMethod: this.verificationMethod, authentication: this.authentication, @@ -32,6 +34,7 @@ export default class DIDDocument { const document = this.document; return { id: this.id, + alsoKnownAs: this.alsoKnownAs, controller: this.controller, verificationMethod: this.document.verificationMethod, authentication: getExistingMethods( document.verificationMethod, document.authentication ), diff --git a/lib/lac1/DIDRegistryRecoverableGM-270-RC1-1f3dc10f.json b/lib/lac1/DIDRegistryRecoverableGM-270-RC1-1f3dc10f.json new file mode 100644 index 0000000..5379519 --- /dev/null +++ b/lib/lac1/DIDRegistryRecoverableGM-270-RC1-1f3dc10f.json @@ -0,0 +1,1285 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "DIDRegistryRecoverableGM", + "sourceName": "contracts/identity/didRegistryGasModel/DIDRegistryRecoverable.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_minKeyRotationTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxAttempts", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_minControllers", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_resetSeconds", + "type": "uint256" + }, + { + "internalType": "address", + "name": "trustedForwarderAddr", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "actor", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "akaId", + "type": "string" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "validTo", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "changeTime", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "previousChange", + "type": "uint256" + } + ], + "name": "AKAChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "name", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "value", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "validTo", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "changeTime", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "previousChange", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "compromised", + "type": "bool" + } + ], + "name": "DIDAttributeChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "actor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newController", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "previousChange", + "type": "uint256" + } + ], + "name": "DIDControllerAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "controller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "previousChange", + "type": "uint256" + } + ], + "name": "DIDControllerChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "actor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "removedController", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "previousChange", + "type": "uint256" + } + ], + "name": "DIDControllerRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "actor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "previousChange", + "type": "uint256" + } + ], + "name": "DIDControllersDeactivated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "actor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "previousChange", + "type": "uint256" + } + ], + "name": "DIDDeactivated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "delegateType", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "address", + "name": "delegate", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "validTo", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "changeTime", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "previousChange", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "compromised", + "type": "bool" + } + ], + "name": "DIDDelegateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "actor", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "keyRotationStatus", + "type": "bool" + } + ], + "name": "KeyRotationStatusChanged", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "accountStatus", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "string", + "name": "akaId", + "type": "string" + }, + { + "internalType": "uint256", + "name": "validity", + "type": "uint256" + } + ], + "name": "addAKAIdentifier", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "address", + "name": "controller", + "type": "address" + } + ], + "name": "addController", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "delegateType", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "delegate", + "type": "address" + }, + { + "internalType": "uint256", + "name": "validity", + "type": "uint256" + } + ], + "name": "addDelegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "uint8", + "name": "sigV", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "sigR", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "sigS", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "delegateType", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "delegate", + "type": "address" + }, + { + "internalType": "uint256", + "name": "validity", + "type": "uint256" + } + ], + "name": "addDelegateSigned", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + } + ], + "name": "areControllersDeactivated", + "outputs": [ + { + "internalType": "bool", + "name": "_areControllersDeactivated", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "attributes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "changed", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "controllers", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + } + ], + "name": "deactivateAccount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + } + ], + "name": "deactivateControllers", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "delegates", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + } + ], + "name": "disableKeyRotation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "uint256", + "name": "keyRotationTime", + "type": "uint256" + } + ], + "name": "enableKeyRotation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "address", + "name": "newController", + "type": "address" + } + ], + "name": "enrollNewAndSetMainController", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "failedAttempts", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + } + ], + "name": "getControllers", + "outputs": [ + { + "internalType": "address[]", + "name": "controllerList", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + } + ], + "name": "identityController", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + } + ], + "name": "isAccountDeactivated", + "outputs": [ + { + "internalType": "bool", + "name": "isDeactivated", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + } + ], + "name": "isKeyRotationEnabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "lastAttempt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minKeyRotationTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "nonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + } + ], + "name": "recover", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "isVoteAdded", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isMainControllerChanged", + "type": "bool" + } + ], + "internalType": "struct IDIDRegistryRecoverable.DIDRecoverResult", + "name": "result", + "type": "tuple" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "uint8", + "name": "sigV", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "sigR", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "sigS", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "backupController", + "type": "address" + } + ], + "name": "recoverSigned", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "isVoteAdded", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isMainControllerChanged", + "type": "bool" + } + ], + "internalType": "struct IDIDRegistryRecoverable.DIDRecoverResult", + "name": "result", + "type": "tuple" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "recoveredKeys", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "string", + "name": "akaId", + "type": "string" + } + ], + "name": "removeAKAIdentifier", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "address", + "name": "controller", + "type": "address" + } + ], + "name": "removeController", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "bytes", + "name": "name", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "value", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "revokeDeltaTime", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "compromised", + "type": "bool" + } + ], + "name": "revokeAttribute", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "uint8", + "name": "sigV", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "sigR", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "sigS", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "name", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "value", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "revokeDeltaTime", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "compromised", + "type": "bool" + } + ], + "name": "revokeAttributeSigned", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "delegateType", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "delegate", + "type": "address" + }, + { + "internalType": "uint256", + "name": "revokeDeltaTime", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "compromised", + "type": "bool" + } + ], + "name": "revokeDelegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "uint8", + "name": "sigV", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "sigR", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "sigS", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "delegateType", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "delegate", + "type": "address" + }, + { + "internalType": "uint256", + "name": "revokeDeltaTime", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "compromised", + "type": "bool" + } + ], + "name": "revokeDelegateSigned", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "address", + "name": "newController", + "type": "address" + } + ], + "name": "rotateMainController", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "uint8", + "name": "sigV", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "sigR", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "sigS", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "newController", + "type": "address" + } + ], + "name": "rotateMainControllerSigned", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "bytes", + "name": "name", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "value", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "validity", + "type": "uint256" + } + ], + "name": "setAttribute", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "uint8", + "name": "sigV", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "sigR", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "sigS", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "name", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "value", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "validity", + "type": "uint256" + } + ], + "name": "setAttributeSigned", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "identity", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "delegateType", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "delegate", + "type": "address" + } + ], + "name": "validDelegate", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": "0x60806040523480156200001157600080fd5b5060405162003cc638038062003cc683398101604081905262000034916200006b565b600694909455600892909255600955600a55600e80546001600160a01b0319166001600160a01b03909216919091179055620000c8565b600080600080600060a086880312156200008457600080fd5b855160208701516040880151606089015160808a0151939850919650945092506001600160a01b0381168114620000ba57600080fd5b809150509295509295909350565b613bee80620000d86000396000f3fe608060405234801561001057600080fd5b50600436106102915760003560e01c8063587f33b511610160578063a385e51e116100d8578063ccbfa4961161008c578063f96d0f9f11610071578063f96d0f9f14610693578063fd6046d7146106b3578063ffb628e2146106d357600080fd5b8063ccbfa4961461066d578063d17cbfff1461068057600080fd5b8063ac546d58116100bd578063ac546d581461063e578063b7dcfc4f14610647578063c7b2864d1461065a57600080fd5b8063a385e51e14610618578063a7068d661461062b57600080fd5b80638b290c221161012f578063921605e111610114578063921605e1146105df5780639478c0d1146105f25780639c2c1b2b1461060557600080fd5b80638b290c221461059d5780638b6fa70b146105cc57600080fd5b8063587f33b5146104d457806361242bdd14610505578063622b2a3c1461053a57806370ae92d21461057d57600080fd5b806321f2de9b1161020e578063390f5e86116101c25780634cd10d4b116101a75780634cd10d4b146104855780634d38c050146104a557806354fd4d50146104b857600080fd5b8063390f5e86146104435780634c57d2c51461047257600080fd5b80632a64490a116101f35780632a64490a146103fd5780632bb884421461041057806332627ec71461042357600080fd5b806321f2de9b146103d757806322b6be68146103ea57600080fd5b80630db3e2f911610265578063130cb5f01161024a578063130cb5f0146103725780631e378f02146103855780631eaf69ba1461039857600080fd5b80630db3e2f91461034c57806311b9eb751461035f57600080fd5b8062bb9412146102965780630684e32a146102ab5780630cd865ec146102db5780630d44625b1461030d575b600080fd5b6102a96102a436600461305b565b6106e6565b005b6102be6102b9366004613094565b610716565b6040516001600160a01b0390911681526020015b60405180910390f35b6102ee6102e93660046130c0565b61074e565b60408051825115158152602092830151151592810192909252016102d2565b61033e61031b3660046130dd565b600160209081526000938452604080852082529284528284209052825290205481565b6040519081526020016102d2565b6102a961035a36600461305b565b610782565b6102a961036d3660046130c0565b6107c6565b6102a96103803660046130c0565b6107f3565b6102a9610393366004613145565b61081d565b6103c76103a63660046130c0565b6001600160a01b031660009081526007602052604090205460ff1660011490565b60405190151581526020016102d2565b6102a96103e536600461329e565b610984565b6102a96103f83660046130c0565b610a63565b6102a961040b366004613344565b610a74565b6102a961041e36600461305b565b610aad565b61033e6104313660046130c0565b600c6020526000908152604090205481565b6103c76104513660046130c0565b6001600160a01b031660009081526007602052604090205460ff1660031490565b6102a961048036600461339f565b610ad9565b61033e6104933660046130c0565b600d6020526000908152604090205481565b6102a96104b33660046133f8565b610af1565b6104c161010e81565b60405161ffff90911681526020016102d2565b61033e6104e2366004613448565b600260209081526000938452604080852082529284528284209052825290205481565b6105286105133660046130c0565b60076020526000908152604090205460ff1681565b60405160ff90911681526020016102d2565b6103c76105483660046130dd565b6001600160a01b0392831660009081526001602090815260408083209483529381528382209290941681529252902054421090565b61033e61058b3660046130c0565b60056020526000908152604090205481565b6103c76105ab3660046130c0565b6001600160a01b031660009081526003602052604090206001015460ff1690565b6102a96105da36600461347d565b610b03565b6102a96105ed366004613094565b610b35565b6102be610600366004613094565b610b47565b6102a9610613366004613502565b610b63565b6102ee610626366004613572565b610cbe565b6102a96106393660046135cf565b610f0b565b61033e60065481565b6102a9610655366004613572565b610f3b565b6102a9610668366004613617565b61107e565b6102a961067b3660046136bb565b611138565b6102a961068e36600461305b565b611168565b61033e6106a13660046130c0565b60046020526000908152604090205481565b6106c66106c13660046130c0565b611194565b6040516102d29190613739565b6102be6106e13660046130c0565b6112b4565b610712826106f26114ed565b6001600160a01b03851660009081526004602052604090205484906114fc565b5050565b600b602052816000526040600020818154811061073257600080fd5b6000918252602090912001546001600160a01b03169150829050565b604080518082019091526000808252602082015261076b826116f3565b61077c826107776114ed565b611721565b92915050565b600061078c6114ed565b6001600160a01b0384166000908152600460205260409020549091506107b4848385846114fc565b6107c084838584611a00565b50505050565b6107f0816107d26114ed565b6001600160a01b038416600090815260046020526040902054611b2d565b50565b6107f0816107ff6114ed565b6001600160a01b038416600090815260046020526040902054611c1e565b60007f1900000000000000000000000000000000000000000000000000000000000000813060058261084e8e6112b4565b6001600160a01b0316815260208082019290925260409081016000205481517fff00000000000000000000000000000000000000000000000000000000000000968716818501529490951660218501527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606093841b8116602286015260368501959095528d831b851660568501527f7265766f6b6544656c6567617465000000000000000000000000000000000000606a850152607884018a90529188901b909316609883015260ac820186905284151560f81b60cc830152805160ad81840301815260cd9092019052805191012090508861097881610952818c8c8c88611cfe565b6001600160a01b0384166000908152600460205260409020548990899089908990611dfd565b50505050505050505050565b60007f190000000000000000000000000000000000000000000000000000000000000081306005826109b58e6112b4565b6001600160a01b03166001600160a01b03168152602001908152602001600020548c898989896040516020016109f3999897969594939291906137aa565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012090508861097881610a3d818c8c8c88611cfe565b6001600160a01b0384166000908152600460205260409020548990899089908990611f08565b6107f081610a6f6114ed565b612039565b610aa685610a806114ed565b6001600160a01b0388166000908152600460205260409020548790879087908790611dfd565b5050505050565b61071282610ab96114ed565b6001600160a01b038516600090815260046020526040902054849061217f565b610aec83610ae56114ed565b84846124ec565b505050565b61071282610afd6114ed565b836125b6565b610aa685610b0f6114ed565b6001600160a01b0388166000908152600460205260409020548790879087908790611f08565b61071282610b416114ed565b8361267c565b6000602052816000526040600020818154811061073257600080fd5b60007f19000000000000000000000000000000000000000000000000000000000000008130600582610b948d6112b4565b6001600160a01b0316815260208082019290925260409081016000205490517fff0000000000000000000000000000000000000000000000000000000000000095861692810192909252929093166021840152606090811b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000908116602285015260368401929092528a811b821660568401527f61646444656c6567617465000000000000000000000000000000000000000000606a8401526075830187905285901b16609582015260a9810183905260c901604051602081830303815290604052805190602001209050610cb488610c908a8a8a8a87611cfe565b6001600160a01b038b16600090815260046020526040902054879087908790612824565b5050505050505050565b6040805180820190915260008082526020820152610cdb866116f3565b6009546001600160a01b0387166000908152602081905260409020541015610d4a5760405162461bcd60e51b815260206004820152600560248201527f4d4e434e4100000000000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b6001600160a01b0382166000818152600560208181526040808420805482517f190000000000000000000000000000000000000000000000000000000000000081860152602181018790527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000030606090811b82166022840152603683018490528f811b821660568401527f7265636f76657200000000000000000000000000000000000000000000000000606a8401528b901b1660718201528351808203606501815260859091019093528251928401929092209585529290915291610e2f836138bb565b90915550506040805160008082526020820180845284905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015610e88573d6000803e3d6000fd5b505050602060405103519050836001600160a01b0316816001600160a01b031614610ef55760405162461bcd60e51b815260206004820152600260248201527f49530000000000000000000000000000000000000000000000000000000000006044820152606401610d41565b610eff8885611721565b98975050505050505050565b6107c084610f176114ed565b6001600160a01b038716600090815260046020526040902054869086908690612824565b60007f19000000000000000000000000000000000000000000000000000000000000008130600582610f6c8b6112b4565b6001600160a01b0316815260208082019290925260409081016000205481517fff00000000000000000000000000000000000000000000000000000000000000968716818501529490951660218501527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606093841b8116602286015260368501959095528a831b851660568501527f726f746174654d61696e436f6e74726f6c6c6572000000000000000000000000606a8501529186901b909316607e830152805160728184030181526092909201905280519101209050611076866110568188888887611cfe565b6001600160a01b0389166000908152600460205260409020548590611a00565b505050505050565b60007f190000000000000000000000000000000000000000000000000000000000000081306005826110af8d6112b4565b6001600160a01b03166001600160a01b03168152602001908152602001600020548b8888886040516020016110eb9897969594939291906138f3565b604051602081830303815290604052805190602001209050610cb4886111148a8a8a8a87611cfe565b6001600160a01b038b1660009081526004602052604090205487908790879061292e565b6107c0846111446114ed565b6001600160a01b03871660009081526004602052604090205486908690869061292e565b610712826111746114ed565b6001600160a01b0385166000908152600460205260409020548490611a00565b6001600160a01b03811660009081526007602052604090205460609060ff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff016111de57919050565b6001600160a01b038216600090815260208181526040918290208054835181840281018401909452808452909183018282801561124457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611226575b50505050509050600081519050806000036112ae5760408051600180825281830190925260009160208083019080368337019050509050838160008151811061128f5761128f6139cb565b6001600160a01b03909216602092830291909101909101529392505050565b50919050565b60006112db826001600160a01b031660009081526007602052604090205460ff1660011490565b8061130157506001600160a01b03821660009081526007602052604090205460ff166003145b1561130e57506000919050565b6001600160a01b03821660009081526020819052604081205490819003611336575090919050565b80600103611383576001600160a01b03831660009081526020819052604081208054909190611367576113676139cb565b6000918252602090912001546001600160a01b03169392505050565b6001600160a01b0383166000908152600360209081526040808320815160608101835281548152600182015460ff161580159482019490945260029091015491810191909152919061143e5760006113f2846113ec856040015142612a0e90919063ffffffff16565b90612a57565b6001600160a01b038716600090815260208190526040902080549192509082908110611420576114206139cb565b6000918252602090912001546001600160a01b031691506114cd9050565b8151831161148b576001600160a01b0385166000908152602081905260408120805490919061146f5761146f6139cb565b6000918252602090912001546001600160a01b031690506114cd565b6001600160a01b03851660009081526020819052604090208251815481106114b5576114b56139cb565b6000918252602090912001546001600160a01b031690505b6001600160a01b038116156114e457949350505050565b50929392505050565b60006114f7612a99565b905090565b8383611507826116f3565b611510826112b4565b6001600160a01b0316816001600160a01b0316146115555760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b60006115618786612cef565b90506000856001600160a01b0316611578896112b4565b6001600160a01b03161480159150600083129082906115945750805b6115e05760405162461bcd60e51b815260206004820152600360248201527f43414500000000000000000000000000000000000000000000000000000000006044820152606401610d41565b6001600160a01b038916600090815260208190526040812054900361164f576001600160a01b0389166000818152602081815260408220805460018101825590835291200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690911790555b6001600160a01b0389811660008181526020818152604080832080546001810182559084529282902090920180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168c861690811790915591518a815291938c1692917f60ca0e880b9d6194f464a35ef9ec9571e82d149df4dc02156be2bc04b0d9715c91015b60405180910390a46116e889612d9e565b505050505050505050565b6001600160a01b03811660009081526007602052604090205460ff1661171881612de0565b61071281612e52565b60408051808201909152600080825260208201526009546001600160a01b038416600090815260208190526040902054101561179f5760405162461bcd60e51b815260206004820152600560248201527f4d4e434e410000000000000000000000000000000000000000000000000000006044820152606401610d41565b6008546001600160a01b0384166000908152600c602052604090205410806117ea5750600a546001600160a01b0384166000908152600d60205260409020546117e890426139fa565b115b6118365760405162461bcd60e51b815260206004820152600260248201527f45410000000000000000000000000000000000000000000000000000000000006044820152606401610d41565b60006118428484612cef565b1261077c57600a546001600160a01b0384166000908152600d602052604090205461186d90426139fa565b11156118a1576001600160a01b0383166000908152600c60209081526040808320839055600b90915281206118a191613014565b6001600160a01b0383166000908152600d602052604081204290556118c68484612ec4565b905060008112611905576001600160a01b0384166000908152600c602052604081208054600192906118f9908490613a0d565b9091555061077c915050565b6001600160a01b038481166000818152600b602090815260408083208054600180820183559185528385200180547fffffffffffffffffffffffff000000000000000000000000000000000000000016968a1696909617909555928252819052205461197d9190611977906002612a0e565b90612f4a565b6001600160a01b0385166000908152600b6020526040902054106119f5576001600160a01b0384166000908152600460205260409020546119c390859081908690611a00565b6001600160a01b0384166000908152600b602052604081206119e491613014565b50600160208201819052815261077c565b506001815292915050565b8383611a0b826116f3565b611a14826112b4565b6001600160a01b0316816001600160a01b031614611a595760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b6000611a658786612cef565b90506000811215611aba5760405162461bcd60e51b8152600401610d419060208082526004908201527f43444e4500000000000000000000000000000000000000000000000000000000604082015260600190565b6001600160a01b0387166000908152600360205260409020819055604080516001600160a01b038781168252602082018790528916917f2a7278c7e47d91c392e2d4f854ebe76d04458b3f431d27ef2e64707e68615e48910160405180910390a2611b2487612d9e565b50505050505050565b8282611b38826116f3565b611b41826112b4565b6001600160a01b0316816001600160a01b031614611b865760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b6001600160a01b0385166000818152600760205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fcb6fb7e3d7dfd4e4cae4fab9cd689a88606957b2682a5bbad47dbf35f62564c290611c0d90879087906001600160a01b03929092168252602082015260400190565b60405180910390a2610aa685612d9e565b8282611c29826116f3565b611c32826112b4565b6001600160a01b0316816001600160a01b031614611c775760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b6001600160a01b0385166000818152600760205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166003179055517f31457df28cffbc88f9dd28782c83bd599cd521df1e106d3de4c1e4b7bfd1f2c690611c0d90879087906001600160a01b03929092168252602082015260400190565b6040805160008082526020820180845284905260ff8716928201929092526060810185905260808101849052819060019060a0016020604051602081039080840390855afa158015611d54573d6000803e3d6000fd5b505050602060405103519050611d69876112b4565b6001600160a01b0316816001600160a01b031614611dc95760405162461bcd60e51b815260206004820152600260248201527f49530000000000000000000000000000000000000000000000000000000000006044820152606401610d41565b6001600160a01b0381166000908152600560205260408120805491611ded836138bb565b9091555090979650505050505050565b8686611e08826116f3565b611e11826112b4565b6001600160a01b0316816001600160a01b031614611e565760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b426000611e6387836139fa565b6001600160a01b038c811660008181526001602090815260408083208f84528252808320948e168084529482529182902085905581518e8152908101939093528201839052606082018590526080820188905288151560a08301529192508c91907fcf1e86a10fb82d2058e61e4994659bc2856278b98466fbff202f41085a4ae7769060c00160405180910390a2611efa81612d9e565b505050505050505050505050565b8686611f13826116f3565b611f1c826112b4565b6001600160a01b0316816001600160a01b031614611f615760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b8651602080890191909120875191880191909120426000611f8289836139fa565b905080600260008f6001600160a01b03166001600160a01b03168152602001908152602001600020600086815260200190815260200160002060008581526020019081526020016000208190555060008d9050806001600160a01b03167feb2ecd6a99853e2a14202b975dae6d0099479291b3bd60759046351dcd1386948d8d85878d8f60405161201896959493929190613a6a565b60405180910390a261202981612d9e565b5050505050505050505050505050565b8181612044826116f3565b61204d826112b4565b6001600160a01b0316816001600160a01b0316146120925760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b6001600160a01b03841660009081526003602052604090206001015460ff16806121005760405162461bcd60e51b8152600401610d419060208082526004908201527f4b52414400000000000000000000000000000000000000000000000000000000604082015260600190565b6001600160a01b03858116600081815260036020908152604080832060010180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551918252928716927f6804a96d9689a545e71b9ad037a8191f732b282c1b07d2447448a8dee2d4fc55910160405180910390a35050505050565b838361218a826116f3565b612193826112b4565b6001600160a01b0316816001600160a01b0316146121d85760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b6001600160a01b0386166000908152602081905260409020546001106122405760405162461bcd60e51b815260206004820152600560248201527f414c5443520000000000000000000000000000000000000000000000000000006044820152606401610d41565b836001600160a01b0316612253876112b4565b6001600160a01b0316036122ab5760405162461bcd60e51b8152600401610d419060208082526004908201527f43444d4300000000000000000000000000000000000000000000000000000000604082015260600190565b60006122b78786612cef565b9050600081121561230c5760405162461bcd60e51b8152600401610d419060208082526004908201527f43444e4500000000000000000000000000000000000000000000000000000000604082015260600190565b6001600160a01b0387166000908152602081905260408120805491906123336001846139fa565b81548110612343576123436139cb565b60009182526020808320909101546001600160a01b038c81168452918390526040909220805491909216925082919085908110612382576123826139cb565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506123b9896112b4565b6001600160a01b0316816001600160a01b0316036123ed576001600160a01b03891660009081526003602052604090208390555b6001600160a01b03891660009081526020819052604090206124106001846139fa565b81548110612420576124206139cb565b6000918252602080832090910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556001600160a01b038b1682528190526040902080548061247557612475613ab7565b6001900381819060005260206000200160006101000a8154906001600160a01b0302191690559055866001600160a01b0316886001600160a01b03168a6001600160a01b03167f6ff3f0d1e8e3a760a66fcc320f8ea7bf6b23efbb25be8bf2f4fc600ffe408ba6896040516116d791815260200190565b83836124f7826116f3565b612500826112b4565b6001600160a01b0316816001600160a01b0316146125455760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b6001600160a01b0380871660008181526004602052604090205442929091908816907f80185ceafcc6fd37e3340eea4098f2a9a6178758e6112374ca4ed6d6c72426ea886125938987613a0d565b86866040516125a59493929190613ae6565b60405180910390a3610cb488612d9e565b82826125c1826116f3565b6125ca826112b4565b6001600160a01b0316816001600160a01b03161461260f5760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b6001600160a01b0380861660008181526004602052604090819020549051429384938a9392918a16917f80185ceafcc6fd37e3340eea4098f2a9a6178758e6112374ca4ed6d6c72426ea9061266b908b90889081908890613ae6565b60405180910390a36116e882612d9e565b8282612687826116f3565b612690826112b4565b6001600160a01b0316816001600160a01b0316146126d55760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b6006548310156127275760405162461bcd60e51b815260206004820152600660248201527f564c5447525400000000000000000000000000000000000000000000000000006044820152606401610d41565b6001600160a01b03851660009081526003602052604090206001015460ff1680156127965760405162461bcd60e51b8152600401610d419060208082526004908201527f4b52414500000000000000000000000000000000000000000000000000000000604082015260600190565b6001600160a01b03868116600081815260036020908152604091829020600180820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168217905560029091018990559151918252928816927f6804a96d9689a545e71b9ad037a8191f732b282c1b07d2447448a8dee2d4fc55910160405180910390a3505050505050565b858561282f826116f3565b612838826112b4565b6001600160a01b0316816001600160a01b03161461287d5760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b426128888582613a0d565b6001600160a01b03808b1660008181526001602090815260408083208d84528252808320948c16835293905291909120919091557fcf1e86a10fb82d2058e61e4994659bc2856278b98466fbff202f41085a4ae77688886128e98986613a0d565b604080519384526001600160a01b039092166020840152908201526060810184905260808101879052600060a082015260c0015b60405180910390a26116e889612d9e565b8585612939826116f3565b612942826112b4565b6001600160a01b0316816001600160a01b0316146129875760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b426129928582613a0d565b6001600160a01b038a1660008181526002602090815260408083208c518d840120845282528083208b518c84012084529091529020919091557feb2ecd6a99853e2a14202b975dae6d0099479291b3bd60759046351dcd13869488886129f88986613a0d565b8589600060405161291d96959493929190613a6a565b6000612a5083836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612fa9565b9392505050565b6000612a5083836040518060400160405280601881526020017f536166654d6174683a206d6f64756c6f206279207a65726f0000000000000000815250612fe0565b600e5460408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f7bdf2ec700000000000000000000000000000000000000000000000000000000179052905160009260609284926001600160a01b0390921691612b129190613b15565b600060405180830381855afa9150503d8060008114612b4d576040519150601f19603f3d011682016040523d82523d6000602084013e612b52565b606091505b509250905080612ba45760405162461bcd60e51b815260206004820152600360248201527f53434600000000000000000000000000000000000000000000000000000000006044820152606401610d41565b81806020019051810190612bb89190613b31565b6001600160a01b03163303612ce757600e5460408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f7a6ce2e10000000000000000000000000000000000000000000000000000000017905290516060926001600160a01b031691612c3891613b15565b600060405180830381855afa9150503d8060008114612c73576040519150601f19603f3d011682016040523d82523d6000602084013e612c78565b606091505b50909250905081612ccb5760405162461bcd60e51b815260206004820152600360248201527f53434600000000000000000000000000000000000000000000000000000000006044820152606401610d41565b80806020019051810190612cdf9190613b31565b935050505090565b339250505090565b6000805b6001600160a01b038416600090815260208190526040902054811015612d75576001600160a01b03848116600090815260208190526040902080549185169183908110612d4257612d426139cb565b6000918252602090912001546001600160a01b031603612d6357905061077c565b80612d6d816138bb565b915050612cf3565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9392505050565b6001600160a01b0381166000908152600460205260409020544390819003612dc4575050565b6001600160a01b03909116600090815260046020526040902055565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd60ff8216016107f05760405162461bcd60e51b815260206004820152600360248201527f41574400000000000000000000000000000000000000000000000000000000006044820152606401610d41565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60ff8216016107f05760405162461bcd60e51b815260206004820152600360248201527f43414400000000000000000000000000000000000000000000000000000000006044820152606401610d41565b6000805b6001600160a01b0384166000908152600b6020526040902054811015612d75576001600160a01b038481166000908152600b6020526040902080549185169183908110612f1757612f176139cb565b6000918252602090912001546001600160a01b031603612f3857905061077c565b80612f42816138bb565b915050612ec8565b600080612f578385613a0d565b905083811015612a505760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610d41565b60008183612fca5760405162461bcd60e51b8152600401610d419190613b4e565b506000612fd78486613b90565b95945050505050565b600081836130015760405162461bcd60e51b8152600401610d419190613b4e565b5061300c8385613ba4565b949350505050565b50805460008255906000526020600020908101906107f091905b80821115613042576000815560010161302e565b5090565b6001600160a01b03811681146107f057600080fd5b6000806040838503121561306e57600080fd5b823561307981613046565b9150602083013561308981613046565b809150509250929050565b600080604083850312156130a757600080fd5b82356130b281613046565b946020939093013593505050565b6000602082840312156130d257600080fd5b8135612a5081613046565b6000806000606084860312156130f257600080fd5b83356130fd81613046565b925060208401359150604084013561311481613046565b809150509250925092565b803560ff8116811461313057600080fd5b919050565b8035801515811461313057600080fd5b600080600080600080600080610100898b03121561316257600080fd5b883561316d81613046565b975061317b60208a0161311f565b965060408901359550606089013594506080890135935060a08901356131a081613046565b925060c089013591506131b560e08a01613135565b90509295985092959890939650565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261320457600080fd5b813567ffffffffffffffff8082111561321f5761321f6131c4565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715613265576132656131c4565b8160405283815286602085880101111561327e57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600080600080610100898b0312156132bb57600080fd5b88356132c681613046565b97506132d460208a0161311f565b96506040890135955060608901359450608089013567ffffffffffffffff808211156132ff57600080fd5b61330b8c838d016131f3565b955060a08b013591508082111561332157600080fd5b5061332e8b828c016131f3565b93505060c089013591506131b560e08a01613135565b600080600080600060a0868803121561335c57600080fd5b853561336781613046565b945060208601359350604086013561337e81613046565b92506060860135915061339360808701613135565b90509295509295909350565b6000806000606084860312156133b457600080fd5b83356133bf81613046565b9250602084013567ffffffffffffffff8111156133db57600080fd5b6133e7868287016131f3565b925050604084013590509250925092565b6000806040838503121561340b57600080fd5b823561341681613046565b9150602083013567ffffffffffffffff81111561343257600080fd5b61343e858286016131f3565b9150509250929050565b60008060006060848603121561345d57600080fd5b833561346881613046565b95602085013595506040909401359392505050565b600080600080600060a0868803121561349557600080fd5b85356134a081613046565b9450602086013567ffffffffffffffff808211156134bd57600080fd5b6134c989838a016131f3565b955060408801359150808211156134df57600080fd5b506134ec888289016131f3565b9350506060860135915061339360808701613135565b600080600080600080600060e0888a03121561351d57600080fd5b873561352881613046565b96506135366020890161311f565b955060408801359450606088013593506080880135925060a088013561355b81613046565b8092505060c0880135905092959891949750929550565b600080600080600060a0868803121561358a57600080fd5b853561359581613046565b94506135a36020870161311f565b9350604086013592506060860135915060808601356135c181613046565b809150509295509295909350565b600080600080608085870312156135e557600080fd5b84356135f081613046565b935060208501359250604085013561360781613046565b9396929550929360600135925050565b600080600080600080600060e0888a03121561363257600080fd5b873561363d81613046565b965061364b6020890161311f565b95506040880135945060608801359350608088013567ffffffffffffffff8082111561367657600080fd5b6136828b838c016131f3565b945060a08a013591508082111561369857600080fd5b506136a58a828b016131f3565b92505060c0880135905092959891949750929550565b600080600080608085870312156136d157600080fd5b84356136dc81613046565b9350602085013567ffffffffffffffff808211156136f957600080fd5b613705888389016131f3565b9450604087013591508082111561371b57600080fd5b50613728878288016131f3565b949793965093946060013593505050565b6020808252825182820181905260009190848201906040850190845b8181101561377a5783516001600160a01b031683529284019291840191600101613755565b50909695505050505050565b60005b838110156137a1578181015183820152602001613789565b50506000910152565b60007fff00000000000000000000000000000000000000000000000000000000000000808c168352808b166001840152507fffffffffffffffffffffffffffffffffffffffff000000000000000000000000808a60601b166002840152886016840152808860601b166036840152507f7265766f6b654174747269627574650000000000000000000000000000000000604a8301528551613852816059850160208a01613786565b855190830190613869816059840160208a01613786565b0160598101949094525050151560f81b6079820152607a01979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036138ec576138ec61388c565b5060010190565b60007fff00000000000000000000000000000000000000000000000000000000000000808b168352808a166001840152507fffffffffffffffffffffffffffffffffffffffff000000000000000000000000808960601b166002840152876016840152808760601b166036840152507f7365744174747269627574650000000000000000000000000000000000000000604a830152845161399b816056850160208901613786565b8451908301906139b2816056840160208901613786565b0160568101939093525050607601979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8181038181111561077c5761077c61388c565b8082018082111561077c5761077c61388c565b60008151808452613a38816020860160208601613786565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60c081526000613a7d60c0830189613a20565b8281036020840152613a8f8189613a20565b91505085604083015284606083015283608083015282151560a0830152979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b608081526000613af96080830187613a20565b6020830195909552506040810192909252606090910152919050565b60008251613b27818460208701613786565b9190910192915050565b600060208284031215613b4357600080fd5b8151612a5081613046565b602081526000612a506020830184613a20565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082613b9f57613b9f613b61565b500490565b600082613bb357613bb3613b61565b50069056fea2646970667358221220b25deb7f05cd42cb625c5b78a88427fe19d8804b4a850f1be20eca17b54bd08164736f6c63430008120033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106102915760003560e01c8063587f33b511610160578063a385e51e116100d8578063ccbfa4961161008c578063f96d0f9f11610071578063f96d0f9f14610693578063fd6046d7146106b3578063ffb628e2146106d357600080fd5b8063ccbfa4961461066d578063d17cbfff1461068057600080fd5b8063ac546d58116100bd578063ac546d581461063e578063b7dcfc4f14610647578063c7b2864d1461065a57600080fd5b8063a385e51e14610618578063a7068d661461062b57600080fd5b80638b290c221161012f578063921605e111610114578063921605e1146105df5780639478c0d1146105f25780639c2c1b2b1461060557600080fd5b80638b290c221461059d5780638b6fa70b146105cc57600080fd5b8063587f33b5146104d457806361242bdd14610505578063622b2a3c1461053a57806370ae92d21461057d57600080fd5b806321f2de9b1161020e578063390f5e86116101c25780634cd10d4b116101a75780634cd10d4b146104855780634d38c050146104a557806354fd4d50146104b857600080fd5b8063390f5e86146104435780634c57d2c51461047257600080fd5b80632a64490a116101f35780632a64490a146103fd5780632bb884421461041057806332627ec71461042357600080fd5b806321f2de9b146103d757806322b6be68146103ea57600080fd5b80630db3e2f911610265578063130cb5f01161024a578063130cb5f0146103725780631e378f02146103855780631eaf69ba1461039857600080fd5b80630db3e2f91461034c57806311b9eb751461035f57600080fd5b8062bb9412146102965780630684e32a146102ab5780630cd865ec146102db5780630d44625b1461030d575b600080fd5b6102a96102a436600461305b565b6106e6565b005b6102be6102b9366004613094565b610716565b6040516001600160a01b0390911681526020015b60405180910390f35b6102ee6102e93660046130c0565b61074e565b60408051825115158152602092830151151592810192909252016102d2565b61033e61031b3660046130dd565b600160209081526000938452604080852082529284528284209052825290205481565b6040519081526020016102d2565b6102a961035a36600461305b565b610782565b6102a961036d3660046130c0565b6107c6565b6102a96103803660046130c0565b6107f3565b6102a9610393366004613145565b61081d565b6103c76103a63660046130c0565b6001600160a01b031660009081526007602052604090205460ff1660011490565b60405190151581526020016102d2565b6102a96103e536600461329e565b610984565b6102a96103f83660046130c0565b610a63565b6102a961040b366004613344565b610a74565b6102a961041e36600461305b565b610aad565b61033e6104313660046130c0565b600c6020526000908152604090205481565b6103c76104513660046130c0565b6001600160a01b031660009081526007602052604090205460ff1660031490565b6102a961048036600461339f565b610ad9565b61033e6104933660046130c0565b600d6020526000908152604090205481565b6102a96104b33660046133f8565b610af1565b6104c161010e81565b60405161ffff90911681526020016102d2565b61033e6104e2366004613448565b600260209081526000938452604080852082529284528284209052825290205481565b6105286105133660046130c0565b60076020526000908152604090205460ff1681565b60405160ff90911681526020016102d2565b6103c76105483660046130dd565b6001600160a01b0392831660009081526001602090815260408083209483529381528382209290941681529252902054421090565b61033e61058b3660046130c0565b60056020526000908152604090205481565b6103c76105ab3660046130c0565b6001600160a01b031660009081526003602052604090206001015460ff1690565b6102a96105da36600461347d565b610b03565b6102a96105ed366004613094565b610b35565b6102be610600366004613094565b610b47565b6102a9610613366004613502565b610b63565b6102ee610626366004613572565b610cbe565b6102a96106393660046135cf565b610f0b565b61033e60065481565b6102a9610655366004613572565b610f3b565b6102a9610668366004613617565b61107e565b6102a961067b3660046136bb565b611138565b6102a961068e36600461305b565b611168565b61033e6106a13660046130c0565b60046020526000908152604090205481565b6106c66106c13660046130c0565b611194565b6040516102d29190613739565b6102be6106e13660046130c0565b6112b4565b610712826106f26114ed565b6001600160a01b03851660009081526004602052604090205484906114fc565b5050565b600b602052816000526040600020818154811061073257600080fd5b6000918252602090912001546001600160a01b03169150829050565b604080518082019091526000808252602082015261076b826116f3565b61077c826107776114ed565b611721565b92915050565b600061078c6114ed565b6001600160a01b0384166000908152600460205260409020549091506107b4848385846114fc565b6107c084838584611a00565b50505050565b6107f0816107d26114ed565b6001600160a01b038416600090815260046020526040902054611b2d565b50565b6107f0816107ff6114ed565b6001600160a01b038416600090815260046020526040902054611c1e565b60007f1900000000000000000000000000000000000000000000000000000000000000813060058261084e8e6112b4565b6001600160a01b0316815260208082019290925260409081016000205481517fff00000000000000000000000000000000000000000000000000000000000000968716818501529490951660218501527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606093841b8116602286015260368501959095528d831b851660568501527f7265766f6b6544656c6567617465000000000000000000000000000000000000606a850152607884018a90529188901b909316609883015260ac820186905284151560f81b60cc830152805160ad81840301815260cd9092019052805191012090508861097881610952818c8c8c88611cfe565b6001600160a01b0384166000908152600460205260409020548990899089908990611dfd565b50505050505050505050565b60007f190000000000000000000000000000000000000000000000000000000000000081306005826109b58e6112b4565b6001600160a01b03166001600160a01b03168152602001908152602001600020548c898989896040516020016109f3999897969594939291906137aa565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012090508861097881610a3d818c8c8c88611cfe565b6001600160a01b0384166000908152600460205260409020548990899089908990611f08565b6107f081610a6f6114ed565b612039565b610aa685610a806114ed565b6001600160a01b0388166000908152600460205260409020548790879087908790611dfd565b5050505050565b61071282610ab96114ed565b6001600160a01b038516600090815260046020526040902054849061217f565b610aec83610ae56114ed565b84846124ec565b505050565b61071282610afd6114ed565b836125b6565b610aa685610b0f6114ed565b6001600160a01b0388166000908152600460205260409020548790879087908790611f08565b61071282610b416114ed565b8361267c565b6000602052816000526040600020818154811061073257600080fd5b60007f19000000000000000000000000000000000000000000000000000000000000008130600582610b948d6112b4565b6001600160a01b0316815260208082019290925260409081016000205490517fff0000000000000000000000000000000000000000000000000000000000000095861692810192909252929093166021840152606090811b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000908116602285015260368401929092528a811b821660568401527f61646444656c6567617465000000000000000000000000000000000000000000606a8401526075830187905285901b16609582015260a9810183905260c901604051602081830303815290604052805190602001209050610cb488610c908a8a8a8a87611cfe565b6001600160a01b038b16600090815260046020526040902054879087908790612824565b5050505050505050565b6040805180820190915260008082526020820152610cdb866116f3565b6009546001600160a01b0387166000908152602081905260409020541015610d4a5760405162461bcd60e51b815260206004820152600560248201527f4d4e434e4100000000000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b6001600160a01b0382166000818152600560208181526040808420805482517f190000000000000000000000000000000000000000000000000000000000000081860152602181018790527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000030606090811b82166022840152603683018490528f811b821660568401527f7265636f76657200000000000000000000000000000000000000000000000000606a8401528b901b1660718201528351808203606501815260859091019093528251928401929092209585529290915291610e2f836138bb565b90915550506040805160008082526020820180845284905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015610e88573d6000803e3d6000fd5b505050602060405103519050836001600160a01b0316816001600160a01b031614610ef55760405162461bcd60e51b815260206004820152600260248201527f49530000000000000000000000000000000000000000000000000000000000006044820152606401610d41565b610eff8885611721565b98975050505050505050565b6107c084610f176114ed565b6001600160a01b038716600090815260046020526040902054869086908690612824565b60007f19000000000000000000000000000000000000000000000000000000000000008130600582610f6c8b6112b4565b6001600160a01b0316815260208082019290925260409081016000205481517fff00000000000000000000000000000000000000000000000000000000000000968716818501529490951660218501527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606093841b8116602286015260368501959095528a831b851660568501527f726f746174654d61696e436f6e74726f6c6c6572000000000000000000000000606a8501529186901b909316607e830152805160728184030181526092909201905280519101209050611076866110568188888887611cfe565b6001600160a01b0389166000908152600460205260409020548590611a00565b505050505050565b60007f190000000000000000000000000000000000000000000000000000000000000081306005826110af8d6112b4565b6001600160a01b03166001600160a01b03168152602001908152602001600020548b8888886040516020016110eb9897969594939291906138f3565b604051602081830303815290604052805190602001209050610cb4886111148a8a8a8a87611cfe565b6001600160a01b038b1660009081526004602052604090205487908790879061292e565b6107c0846111446114ed565b6001600160a01b03871660009081526004602052604090205486908690869061292e565b610712826111746114ed565b6001600160a01b0385166000908152600460205260409020548490611a00565b6001600160a01b03811660009081526007602052604090205460609060ff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff016111de57919050565b6001600160a01b038216600090815260208181526040918290208054835181840281018401909452808452909183018282801561124457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611226575b50505050509050600081519050806000036112ae5760408051600180825281830190925260009160208083019080368337019050509050838160008151811061128f5761128f6139cb565b6001600160a01b03909216602092830291909101909101529392505050565b50919050565b60006112db826001600160a01b031660009081526007602052604090205460ff1660011490565b8061130157506001600160a01b03821660009081526007602052604090205460ff166003145b1561130e57506000919050565b6001600160a01b03821660009081526020819052604081205490819003611336575090919050565b80600103611383576001600160a01b03831660009081526020819052604081208054909190611367576113676139cb565b6000918252602090912001546001600160a01b03169392505050565b6001600160a01b0383166000908152600360209081526040808320815160608101835281548152600182015460ff161580159482019490945260029091015491810191909152919061143e5760006113f2846113ec856040015142612a0e90919063ffffffff16565b90612a57565b6001600160a01b038716600090815260208190526040902080549192509082908110611420576114206139cb565b6000918252602090912001546001600160a01b031691506114cd9050565b8151831161148b576001600160a01b0385166000908152602081905260408120805490919061146f5761146f6139cb565b6000918252602090912001546001600160a01b031690506114cd565b6001600160a01b03851660009081526020819052604090208251815481106114b5576114b56139cb565b6000918252602090912001546001600160a01b031690505b6001600160a01b038116156114e457949350505050565b50929392505050565b60006114f7612a99565b905090565b8383611507826116f3565b611510826112b4565b6001600160a01b0316816001600160a01b0316146115555760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b60006115618786612cef565b90506000856001600160a01b0316611578896112b4565b6001600160a01b03161480159150600083129082906115945750805b6115e05760405162461bcd60e51b815260206004820152600360248201527f43414500000000000000000000000000000000000000000000000000000000006044820152606401610d41565b6001600160a01b038916600090815260208190526040812054900361164f576001600160a01b0389166000818152602081815260408220805460018101825590835291200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690911790555b6001600160a01b0389811660008181526020818152604080832080546001810182559084529282902090920180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168c861690811790915591518a815291938c1692917f60ca0e880b9d6194f464a35ef9ec9571e82d149df4dc02156be2bc04b0d9715c91015b60405180910390a46116e889612d9e565b505050505050505050565b6001600160a01b03811660009081526007602052604090205460ff1661171881612de0565b61071281612e52565b60408051808201909152600080825260208201526009546001600160a01b038416600090815260208190526040902054101561179f5760405162461bcd60e51b815260206004820152600560248201527f4d4e434e410000000000000000000000000000000000000000000000000000006044820152606401610d41565b6008546001600160a01b0384166000908152600c602052604090205410806117ea5750600a546001600160a01b0384166000908152600d60205260409020546117e890426139fa565b115b6118365760405162461bcd60e51b815260206004820152600260248201527f45410000000000000000000000000000000000000000000000000000000000006044820152606401610d41565b60006118428484612cef565b1261077c57600a546001600160a01b0384166000908152600d602052604090205461186d90426139fa565b11156118a1576001600160a01b0383166000908152600c60209081526040808320839055600b90915281206118a191613014565b6001600160a01b0383166000908152600d602052604081204290556118c68484612ec4565b905060008112611905576001600160a01b0384166000908152600c602052604081208054600192906118f9908490613a0d565b9091555061077c915050565b6001600160a01b038481166000818152600b602090815260408083208054600180820183559185528385200180547fffffffffffffffffffffffff000000000000000000000000000000000000000016968a1696909617909555928252819052205461197d9190611977906002612a0e565b90612f4a565b6001600160a01b0385166000908152600b6020526040902054106119f5576001600160a01b0384166000908152600460205260409020546119c390859081908690611a00565b6001600160a01b0384166000908152600b602052604081206119e491613014565b50600160208201819052815261077c565b506001815292915050565b8383611a0b826116f3565b611a14826112b4565b6001600160a01b0316816001600160a01b031614611a595760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b6000611a658786612cef565b90506000811215611aba5760405162461bcd60e51b8152600401610d419060208082526004908201527f43444e4500000000000000000000000000000000000000000000000000000000604082015260600190565b6001600160a01b0387166000908152600360205260409020819055604080516001600160a01b038781168252602082018790528916917f2a7278c7e47d91c392e2d4f854ebe76d04458b3f431d27ef2e64707e68615e48910160405180910390a2611b2487612d9e565b50505050505050565b8282611b38826116f3565b611b41826112b4565b6001600160a01b0316816001600160a01b031614611b865760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b6001600160a01b0385166000818152600760205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fcb6fb7e3d7dfd4e4cae4fab9cd689a88606957b2682a5bbad47dbf35f62564c290611c0d90879087906001600160a01b03929092168252602082015260400190565b60405180910390a2610aa685612d9e565b8282611c29826116f3565b611c32826112b4565b6001600160a01b0316816001600160a01b031614611c775760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b6001600160a01b0385166000818152600760205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166003179055517f31457df28cffbc88f9dd28782c83bd599cd521df1e106d3de4c1e4b7bfd1f2c690611c0d90879087906001600160a01b03929092168252602082015260400190565b6040805160008082526020820180845284905260ff8716928201929092526060810185905260808101849052819060019060a0016020604051602081039080840390855afa158015611d54573d6000803e3d6000fd5b505050602060405103519050611d69876112b4565b6001600160a01b0316816001600160a01b031614611dc95760405162461bcd60e51b815260206004820152600260248201527f49530000000000000000000000000000000000000000000000000000000000006044820152606401610d41565b6001600160a01b0381166000908152600560205260408120805491611ded836138bb565b9091555090979650505050505050565b8686611e08826116f3565b611e11826112b4565b6001600160a01b0316816001600160a01b031614611e565760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b426000611e6387836139fa565b6001600160a01b038c811660008181526001602090815260408083208f84528252808320948e168084529482529182902085905581518e8152908101939093528201839052606082018590526080820188905288151560a08301529192508c91907fcf1e86a10fb82d2058e61e4994659bc2856278b98466fbff202f41085a4ae7769060c00160405180910390a2611efa81612d9e565b505050505050505050505050565b8686611f13826116f3565b611f1c826112b4565b6001600160a01b0316816001600160a01b031614611f615760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b8651602080890191909120875191880191909120426000611f8289836139fa565b905080600260008f6001600160a01b03166001600160a01b03168152602001908152602001600020600086815260200190815260200160002060008581526020019081526020016000208190555060008d9050806001600160a01b03167feb2ecd6a99853e2a14202b975dae6d0099479291b3bd60759046351dcd1386948d8d85878d8f60405161201896959493929190613a6a565b60405180910390a261202981612d9e565b5050505050505050505050505050565b8181612044826116f3565b61204d826112b4565b6001600160a01b0316816001600160a01b0316146120925760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b6001600160a01b03841660009081526003602052604090206001015460ff16806121005760405162461bcd60e51b8152600401610d419060208082526004908201527f4b52414400000000000000000000000000000000000000000000000000000000604082015260600190565b6001600160a01b03858116600081815260036020908152604080832060010180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551918252928716927f6804a96d9689a545e71b9ad037a8191f732b282c1b07d2447448a8dee2d4fc55910160405180910390a35050505050565b838361218a826116f3565b612193826112b4565b6001600160a01b0316816001600160a01b0316146121d85760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b6001600160a01b0386166000908152602081905260409020546001106122405760405162461bcd60e51b815260206004820152600560248201527f414c5443520000000000000000000000000000000000000000000000000000006044820152606401610d41565b836001600160a01b0316612253876112b4565b6001600160a01b0316036122ab5760405162461bcd60e51b8152600401610d419060208082526004908201527f43444d4300000000000000000000000000000000000000000000000000000000604082015260600190565b60006122b78786612cef565b9050600081121561230c5760405162461bcd60e51b8152600401610d419060208082526004908201527f43444e4500000000000000000000000000000000000000000000000000000000604082015260600190565b6001600160a01b0387166000908152602081905260408120805491906123336001846139fa565b81548110612343576123436139cb565b60009182526020808320909101546001600160a01b038c81168452918390526040909220805491909216925082919085908110612382576123826139cb565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506123b9896112b4565b6001600160a01b0316816001600160a01b0316036123ed576001600160a01b03891660009081526003602052604090208390555b6001600160a01b03891660009081526020819052604090206124106001846139fa565b81548110612420576124206139cb565b6000918252602080832090910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556001600160a01b038b1682528190526040902080548061247557612475613ab7565b6001900381819060005260206000200160006101000a8154906001600160a01b0302191690559055866001600160a01b0316886001600160a01b03168a6001600160a01b03167f6ff3f0d1e8e3a760a66fcc320f8ea7bf6b23efbb25be8bf2f4fc600ffe408ba6896040516116d791815260200190565b83836124f7826116f3565b612500826112b4565b6001600160a01b0316816001600160a01b0316146125455760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b6001600160a01b0380871660008181526004602052604090205442929091908816907f80185ceafcc6fd37e3340eea4098f2a9a6178758e6112374ca4ed6d6c72426ea886125938987613a0d565b86866040516125a59493929190613ae6565b60405180910390a3610cb488612d9e565b82826125c1826116f3565b6125ca826112b4565b6001600160a01b0316816001600160a01b03161461260f5760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b6001600160a01b0380861660008181526004602052604090819020549051429384938a9392918a16917f80185ceafcc6fd37e3340eea4098f2a9a6178758e6112374ca4ed6d6c72426ea9061266b908b90889081908890613ae6565b60405180910390a36116e882612d9e565b8282612687826116f3565b612690826112b4565b6001600160a01b0316816001600160a01b0316146126d55760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b6006548310156127275760405162461bcd60e51b815260206004820152600660248201527f564c5447525400000000000000000000000000000000000000000000000000006044820152606401610d41565b6001600160a01b03851660009081526003602052604090206001015460ff1680156127965760405162461bcd60e51b8152600401610d419060208082526004908201527f4b52414500000000000000000000000000000000000000000000000000000000604082015260600190565b6001600160a01b03868116600081815260036020908152604091829020600180820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168217905560029091018990559151918252928816927f6804a96d9689a545e71b9ad037a8191f732b282c1b07d2447448a8dee2d4fc55910160405180910390a3505050505050565b858561282f826116f3565b612838826112b4565b6001600160a01b0316816001600160a01b03161461287d5760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b426128888582613a0d565b6001600160a01b03808b1660008181526001602090815260408083208d84528252808320948c16835293905291909120919091557fcf1e86a10fb82d2058e61e4994659bc2856278b98466fbff202f41085a4ae77688886128e98986613a0d565b604080519384526001600160a01b039092166020840152908201526060810184905260808101879052600060a082015260c0015b60405180910390a26116e889612d9e565b8585612939826116f3565b612942826112b4565b6001600160a01b0316816001600160a01b0316146129875760405162461bcd60e51b81526020600482015260026024820152614e4160f01b6044820152606401610d41565b426129928582613a0d565b6001600160a01b038a1660008181526002602090815260408083208c518d840120845282528083208b518c84012084529091529020919091557feb2ecd6a99853e2a14202b975dae6d0099479291b3bd60759046351dcd13869488886129f88986613a0d565b8589600060405161291d96959493929190613a6a565b6000612a5083836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612fa9565b9392505050565b6000612a5083836040518060400160405280601881526020017f536166654d6174683a206d6f64756c6f206279207a65726f0000000000000000815250612fe0565b600e5460408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f7bdf2ec700000000000000000000000000000000000000000000000000000000179052905160009260609284926001600160a01b0390921691612b129190613b15565b600060405180830381855afa9150503d8060008114612b4d576040519150601f19603f3d011682016040523d82523d6000602084013e612b52565b606091505b509250905080612ba45760405162461bcd60e51b815260206004820152600360248201527f53434600000000000000000000000000000000000000000000000000000000006044820152606401610d41565b81806020019051810190612bb89190613b31565b6001600160a01b03163303612ce757600e5460408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f7a6ce2e10000000000000000000000000000000000000000000000000000000017905290516060926001600160a01b031691612c3891613b15565b600060405180830381855afa9150503d8060008114612c73576040519150601f19603f3d011682016040523d82523d6000602084013e612c78565b606091505b50909250905081612ccb5760405162461bcd60e51b815260206004820152600360248201527f53434600000000000000000000000000000000000000000000000000000000006044820152606401610d41565b80806020019051810190612cdf9190613b31565b935050505090565b339250505090565b6000805b6001600160a01b038416600090815260208190526040902054811015612d75576001600160a01b03848116600090815260208190526040902080549185169183908110612d4257612d426139cb565b6000918252602090912001546001600160a01b031603612d6357905061077c565b80612d6d816138bb565b915050612cf3565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9392505050565b6001600160a01b0381166000908152600460205260409020544390819003612dc4575050565b6001600160a01b03909116600090815260046020526040902055565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd60ff8216016107f05760405162461bcd60e51b815260206004820152600360248201527f41574400000000000000000000000000000000000000000000000000000000006044820152606401610d41565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60ff8216016107f05760405162461bcd60e51b815260206004820152600360248201527f43414400000000000000000000000000000000000000000000000000000000006044820152606401610d41565b6000805b6001600160a01b0384166000908152600b6020526040902054811015612d75576001600160a01b038481166000908152600b6020526040902080549185169183908110612f1757612f176139cb565b6000918252602090912001546001600160a01b031603612f3857905061077c565b80612f42816138bb565b915050612ec8565b600080612f578385613a0d565b905083811015612a505760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610d41565b60008183612fca5760405162461bcd60e51b8152600401610d419190613b4e565b506000612fd78486613b90565b95945050505050565b600081836130015760405162461bcd60e51b8152600401610d419190613b4e565b5061300c8385613ba4565b949350505050565b50805460008255906000526020600020908101906107f091905b80821115613042576000815560010161302e565b5090565b6001600160a01b03811681146107f057600080fd5b6000806040838503121561306e57600080fd5b823561307981613046565b9150602083013561308981613046565b809150509250929050565b600080604083850312156130a757600080fd5b82356130b281613046565b946020939093013593505050565b6000602082840312156130d257600080fd5b8135612a5081613046565b6000806000606084860312156130f257600080fd5b83356130fd81613046565b925060208401359150604084013561311481613046565b809150509250925092565b803560ff8116811461313057600080fd5b919050565b8035801515811461313057600080fd5b600080600080600080600080610100898b03121561316257600080fd5b883561316d81613046565b975061317b60208a0161311f565b965060408901359550606089013594506080890135935060a08901356131a081613046565b925060c089013591506131b560e08a01613135565b90509295985092959890939650565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261320457600080fd5b813567ffffffffffffffff8082111561321f5761321f6131c4565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715613265576132656131c4565b8160405283815286602085880101111561327e57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600080600080610100898b0312156132bb57600080fd5b88356132c681613046565b97506132d460208a0161311f565b96506040890135955060608901359450608089013567ffffffffffffffff808211156132ff57600080fd5b61330b8c838d016131f3565b955060a08b013591508082111561332157600080fd5b5061332e8b828c016131f3565b93505060c089013591506131b560e08a01613135565b600080600080600060a0868803121561335c57600080fd5b853561336781613046565b945060208601359350604086013561337e81613046565b92506060860135915061339360808701613135565b90509295509295909350565b6000806000606084860312156133b457600080fd5b83356133bf81613046565b9250602084013567ffffffffffffffff8111156133db57600080fd5b6133e7868287016131f3565b925050604084013590509250925092565b6000806040838503121561340b57600080fd5b823561341681613046565b9150602083013567ffffffffffffffff81111561343257600080fd5b61343e858286016131f3565b9150509250929050565b60008060006060848603121561345d57600080fd5b833561346881613046565b95602085013595506040909401359392505050565b600080600080600060a0868803121561349557600080fd5b85356134a081613046565b9450602086013567ffffffffffffffff808211156134bd57600080fd5b6134c989838a016131f3565b955060408801359150808211156134df57600080fd5b506134ec888289016131f3565b9350506060860135915061339360808701613135565b600080600080600080600060e0888a03121561351d57600080fd5b873561352881613046565b96506135366020890161311f565b955060408801359450606088013593506080880135925060a088013561355b81613046565b8092505060c0880135905092959891949750929550565b600080600080600060a0868803121561358a57600080fd5b853561359581613046565b94506135a36020870161311f565b9350604086013592506060860135915060808601356135c181613046565b809150509295509295909350565b600080600080608085870312156135e557600080fd5b84356135f081613046565b935060208501359250604085013561360781613046565b9396929550929360600135925050565b600080600080600080600060e0888a03121561363257600080fd5b873561363d81613046565b965061364b6020890161311f565b95506040880135945060608801359350608088013567ffffffffffffffff8082111561367657600080fd5b6136828b838c016131f3565b945060a08a013591508082111561369857600080fd5b506136a58a828b016131f3565b92505060c0880135905092959891949750929550565b600080600080608085870312156136d157600080fd5b84356136dc81613046565b9350602085013567ffffffffffffffff808211156136f957600080fd5b613705888389016131f3565b9450604087013591508082111561371b57600080fd5b50613728878288016131f3565b949793965093946060013593505050565b6020808252825182820181905260009190848201906040850190845b8181101561377a5783516001600160a01b031683529284019291840191600101613755565b50909695505050505050565b60005b838110156137a1578181015183820152602001613789565b50506000910152565b60007fff00000000000000000000000000000000000000000000000000000000000000808c168352808b166001840152507fffffffffffffffffffffffffffffffffffffffff000000000000000000000000808a60601b166002840152886016840152808860601b166036840152507f7265766f6b654174747269627574650000000000000000000000000000000000604a8301528551613852816059850160208a01613786565b855190830190613869816059840160208a01613786565b0160598101949094525050151560f81b6079820152607a01979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036138ec576138ec61388c565b5060010190565b60007fff00000000000000000000000000000000000000000000000000000000000000808b168352808a166001840152507fffffffffffffffffffffffffffffffffffffffff000000000000000000000000808960601b166002840152876016840152808760601b166036840152507f7365744174747269627574650000000000000000000000000000000000000000604a830152845161399b816056850160208901613786565b8451908301906139b2816056840160208901613786565b0160568101939093525050607601979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8181038181111561077c5761077c61388c565b8082018082111561077c5761077c61388c565b60008151808452613a38816020860160208601613786565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60c081526000613a7d60c0830189613a20565b8281036020840152613a8f8189613a20565b91505085604083015284606083015283608083015282151560a0830152979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b608081526000613af96080830187613a20565b6020830195909552506040810192909252606090910152919050565b60008251613b27818460208701613786565b9190910192915050565b600060208284031215613b4357600080fd5b8151612a5081613046565b602081526000612a506020830184613a20565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082613b9f57613b9f613b61565b500490565b600082613bb357613bb3613b61565b50069056fea2646970667358221220b25deb7f05cd42cb625c5b78a88427fe19d8804b4a850f1be20eca17b54bd08164736f6c63430008120033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/lib/lac1/lac1Did.js b/lib/lac1/lac1Did.js index 6770570..f81266e 100644 --- a/lib/lac1/lac1Did.js +++ b/lib/lac1/lac1Did.js @@ -1,9 +1,9 @@ import { keccak256 } from "ethers/lib/utils.js"; import DID from "../did.js"; -import * as ethers from 'ethers'; +import * as ethers from "ethers"; import base58 from "bs58"; import lacchain from "@lacchain/gas-model-provider"; -import DIDRegistryContractGM from "./DIDRegistryGM.json"; +import DIDRegistryContractGM from "./DIDRegistryRecoverableGM-270-RC1-1f3dc10f.json"; import DIDRegistryContract from "./DIDRegistry.json"; import { getResolver } from "./resolver.js"; import Lac1DIDRegistry from "./lac1registry.js"; @@ -169,6 +169,27 @@ export default class DIDLac1 extends DID { return await this.resolver.lac1(did); } + async changeController(controller) { + if (this.readOnly) + throw new Error("Cannot change controller to a read-only DID"); + const tx = await this.registry.rotateMainController( + this.address, + controller + ); + return await tx.wait(); + } + + async changeControllerSigned(controllerPrivateKey, controller) { + if (this.readOnly) + throw new Error("Cannot change controller to a read-only DID"); + const tx = await this.registry.rotateMainControllerSigned( + this.address, + controllerPrivateKey, + controller + ); + return await tx.wait(); + } + async revokeVerificationMethod(vm) { if (this.readOnly) throw new Error("Cannot revoke verification method to a read-only DID"); @@ -181,4 +202,17 @@ export default class DIDLac1 extends DID { ); return await tx.wait(); } + + async addAKAId(id, validity) { + if (this.readOnly) + throw new Error("Cannot add alsoKnownAs element to a read-only DID"); + const tx = await this.registry.addAKAIdentifier(this.address, id, validity); + return await tx.wait(); + } + async removeAKAId(id) { + if (this.readOnly) + throw new Error("Cannot remove alsoKnownAs element to a read-only DID"); + const tx = await this.registry.removeAKAIdentifier(this.address, id); + return await tx.wait(); + } } diff --git a/lib/lac1/lac1registry.js b/lib/lac1/lac1registry.js index d9e03d0..7f0ff2d 100644 --- a/lib/lac1/lac1registry.js +++ b/lib/lac1/lac1registry.js @@ -1,15 +1,19 @@ import * as ethers from "ethers"; import DIDRegistry from "../registry.js"; -import { attributeToHex, stringToBytes } from "../utils.js"; -import DIDRegistryContractGM from "./DIDRegistryGM.json"; +import { + attributeToHex, + stripHexPrefix, + stringToBytes, + signData, +} from "../utils.js"; +import DIDRegistryContractGM from "./DIDRegistryRecoverableGM-270-RC1-1f3dc10f.json"; import DIDRegistryContract from "./DIDRegistry.json"; - export default class Lac1DIDRegistry extends DIDRegistry { constructor(conf = {}) { super(conf); this.registry = new ethers.Contract( conf.registry, - conf.nodeAddress ? DIDRegistryContractGM.abi : DIDRegistryContract.abi, + conf.nodeAddress ? DIDRegistryContractGM.abi : DIDRegistryContract.abi, // TODO: Update DID Reg for no-gas-model network this.provider ); } @@ -33,4 +37,52 @@ export default class Lac1DIDRegistry extends DIDRegistry { } ); } + + rotateMainController(address, newController) { + return this.registry.rotateMainController(address, newController, { + gasLimit: 1000000, + gasPrice: 0, + }); + } + + async rotateMainControllerSigned( + address, + controllerPrivateKey, + newController + ) { + const nonce = await this.registry.nonce(newController); + const sig = await signData( + address, + controllerPrivateKey, + Buffer.from("rotateMainController").toString("hex") + + stripHexPrefix(newController), + nonce.toNumber(), + this.conf.registry + ); + return await this.registry.rotateMainControllerSigned( + address, + sig.v, + sig.r, + sig.s, + newController, + { + gasLimit: 1000000, + gasPrice: 0, + } + ); + } + + async addAKAIdentifier(address, id, validity) { + return this.registry.addAKAIdentifier(address, id, validity, { + gasLimit: 1000000, + gasPrice: 0, + }); // TODO: generalize for non gas model networks + } + + async removeAKAIdentifier(address, id) { + return this.registry.removeAKAIdentifier(address, id, { + gasLimit: 1000000, + gasPrice: 0, + }); // TODO: generalize for non gas model networks + } } diff --git a/lib/lac1/lac1resolverUtils.js b/lib/lac1/lac1resolverUtils.js new file mode 100644 index 0000000..dabfcfe --- /dev/null +++ b/lib/lac1/lac1resolverUtils.js @@ -0,0 +1,244 @@ +import bs58 from "bs58"; +import * as ethers from "ethers"; +import DIDDocument from "../document.js"; +import { bytes32toString, keyAlgorithms } from "../utils.js"; +import { keccak256 } from "ethers/lib/utils.js"; + +const { BigNumber } = ethers; + +export function processVerificationMethodIdForAttribute(prefix, valueInHex) { + const valueArrayBuffer = Buffer.from(valueInHex.replace("0x", ""), "hex"); + const prefixBuffer = Buffer.from(prefix, "utf-8"); + const finalBuffer = Buffer.concat([prefixBuffer, valueArrayBuffer]); + const digest = keccak256(finalBuffer); + const bufferDigest = Buffer.from(digest.replace("0x", ""), "hex"); + const base58Identifier = bs58.encode(bufferDigest); + return base58Identifier; +} + +export function getVerificationMethod(did, algo, encoding, value, controller) { + const id = processVerificationMethodIdForAttribute(controller, value); + const verificationMethod = { + id: `${did}#${id}`, + type: `${keyAlgorithms[algo]}`, + controller, + }; + switch (encoding) { + case null: + case undefined: + case "hex": + verificationMethod.publicKeyHex = value.slice(2); + break; + case "blockchain": + verificationMethod.blockchainAccountId = value; + break; + case "base64": + verificationMethod.publicKeyBase64 = Buffer.from( + value.slice(2), + "hex" + ).toString("base64"); + break; + case "base58": + verificationMethod.publicKeyBase58 = bs58.encode( + Buffer.from(value.slice(2), "hex") + ); + break; + case "pem": + verificationMethod.publicKeyPem = Buffer.from( + value.slice(2), + "hex" + ).toString(); + break; + case "json": + verificationMethod.publicKeyJwk = JSON.parse( + Buffer.from(value.slice(2), "hex").toString() + ); + break; + } + return verificationMethod; +} + +export function processValidVerificationMethod( + did, + event, + verificationMethods, + services, + relationships, + value, + key +) { + const name = bytes32toString(event.args.name); + const match = name.match( + /(vm|auth|asse|keya|dele|invo|svc)\/(.+)?\/(\w+)?\/(\w+)?$/ + ); + if (!match) return; + const type = match[1]; + const controller = match[2]; + const algo = match[3]; + const encoding = match[4]; + switch (type) { + case "vm": + verificationMethods[key] = getVerificationMethod( + did, + algo, + encoding, + value, + controller + ); + break; + case "auth": + case "asse": + case "keya": + case "dele": + case "invo": + if (!algo && !encoding) { + relationships[type][key] = Buffer.from( + value.slice(2), + "hex" + ).toString(); + return; + } + verificationMethods[key] = getVerificationMethod( + did, + algo, + encoding, + value, + controller + ); + relationships[type][key] = verificationMethods[key].id; + break; + case "svc": + services[key] = { + id: processVerificationMethodIdForAttribute(type, value), + type: algo, + serviceEndpoint: Buffer.from( + event.args.value.slice(2), + "hex" + ).toString(), + }; + break; + } +} + +export function handleVerificationMethodRemoval( + relationships, + verificationMethods, + services, + key +) { + delete relationships.auth[key]; + delete relationships.asse[key]; + delete relationships.keya[key]; + delete relationships.dele[key]; + delete relationships.invo[key]; + delete verificationMethods[key]; + delete services[key]; +} + +export function processAKAEventsOnAddingAnElement(id, alsoKnownAs) { + const idx = alsoKnownAs.indexOf(id); + if (idx < 0) { + alsoKnownAs.push(id); + } +} + +export function processAKAEventsOnRemovingElement(id, alsoKnownAs) { + const idx = alsoKnownAs.indexOf(id); + if (idx > -1) { + alsoKnownAs.splice(idx, 1); + } +} + +export function wrapDidDocument( + did, + caip10ControllerFormat, + controller, + history, + mode +) { + const now = BigNumber.from(Math.floor(new Date().getTime() / 1000)); + const valueInHex = caip10ControllerFormat.split(":")[2]; + const defaultIdVerificationMethod = processVerificationMethodIdForAttribute( + did, + valueInHex + ); + const defaultVerificationMethod = { + id: `${did}#${defaultIdVerificationMethod}`, + type: "EcdsaSecp256k1RecoveryMethod2020", + controller: `${did}`, + blockchainAccountId: caip10ControllerFormat, + }; + const relationships = { + auth: {}, + asse: {}, + keya: {}, + dele: {}, + invo: {}, + }; + const verificationMethods = {}; + const services = {}; + const alsoKnownAs = []; + for (const event of history) { + const validTo = event.args.validTo; + const key = `${event.name}-${event.args.name}-${event.args.value}`; + const value = event.args.value; + if (validTo && validTo.gte(now)) { + if (event.name == "DIDAttributeChanged") { + processValidVerificationMethod( + did, + event, + verificationMethods, + services, + relationships, + value, + key + ); + } else if (event.name == "AKAChanged") { + const id = event.args.akaId; + processAKAEventsOnAddingAnElement(id, alsoKnownAs); + } + } else { + if (event.name == "DIDAttributeChanged") { + handleVerificationMethodRemoval( + relationships, + verificationMethods, + services, + key + ); + } else if (event.name == "AKAChanged") { + const id = event.args.akaId; + processAKAEventsOnRemovingElement(id, alsoKnownAs); + } + } + } + + const doc = { + "@context": [ + "https://w3id.org/did/v1", + "https://w3id.org/security/suites/jws-2020/v1", + ], + id: did, + alsoKnownAs, + controller, + verificationMethod: [defaultVerificationMethod].concat( + Object.values(verificationMethods) + ), + authentication: [] + .concat([defaultVerificationMethod.id]) + .concat(Object.values(relationships.auth)), + assertionMethod: [] + .concat([defaultVerificationMethod.id]) + .concat(Object.values(relationships.asse)), + keyAgreement: [].concat(Object.values(relationships.keya)), + capabilityInvocation: [].concat(Object.values(relationships.invo)), + capabilityDelegation: [].concat(Object.values(relationships.dele)), + }; + + if (Object.values(services).length > 0) { + doc.service = Object.values(services); + } + + if (alsoKnownAs.length == 0) delete doc.alsoKnownAs; + + return new DIDDocument(doc, mode); +} diff --git a/lib/lac1/resolver.js b/lib/lac1/resolver.js index 461d924..dc7dc6a 100644 --- a/lib/lac1/resolver.js +++ b/lib/lac1/resolver.js @@ -1,7 +1,7 @@ import * as ethers from "ethers"; -import DIDRegistryContractGM from "./DIDRegistryGM.json"; +import DIDRegistryContractGM from "./DIDRegistryRecoverableGM-270-RC1-1f3dc10f.json"; import lacchain from "@lacchain/gas-model-provider"; -import { wrapDidDocument } from "../resolver.js"; +import { wrapDidDocument } from "./lac1resolverUtils.js"; import DIDLac1 from "./lac1Did.js"; import { LAC1_DID_TYPE_CODE } from "./constants.js"; @@ -43,8 +43,9 @@ export function getResolver(config = {}) { } catch (e) { throw new Error("Invalid DID"); } + const intDecodedChainId = parseInt(decodedDid.chainId.substring(2), 16); const network = config.networks.find( - (net) => net.chainId === parseInt(decodedDid.chainId.substring(2), 16) + (net) => net.chainId === intDecodedChainId ); if (!network) throw new Error(`No available network for the passed did`); let provider = new ethers.providers.JsonRpcProvider(network.rpcUrl); @@ -67,9 +68,10 @@ export function getResolver(config = {}) { decodedDid.didRegistryAddress, decodedDid.version // TODO: check side effects of assuming same version for both the main identity and controller did ); + const caip10ControllerFormat = `eip155:${intDecodedChainId}:${controller}`; return wrapDidDocument( did, - decodedDid.address, + caip10ControllerFormat, `did:lac1:${encodedController}`, history, config.mode diff --git a/lib/registryrecoverable.js b/lib/registryrecoverable.js index cce5daf..943fc89 100644 --- a/lib/registryrecoverable.js +++ b/lib/registryrecoverable.js @@ -1,20 +1,29 @@ -import DIDRegistry from './registry.js'; +import DIDRegistry from "./registry.js"; import * as ethers from "ethers"; import DIDRegistryRecoverableContract from "./DIDRegistryRecoverable.json"; export default class DIDRegistryRecoverable extends DIDRegistry { + constructor(conf = {}) { + super(conf); + const provider = this.configureProvider(conf); + this.registry = new ethers.Contract( + conf.registry, + DIDRegistryRecoverableContract.abi, + provider + ); + } - constructor( conf = {} ) { - super( conf ); - const provider = this.configureProvider( conf ); - this.registry = new ethers.Contract( conf.registry, DIDRegistryRecoverableContract.abi, provider ); - } - - recover( address, signature, controller ) { - return this.registry.recover( address, signature.v, signature.r, signature.s, controller, { - gasLimit: 10000000, - gasPrice: 0 - } ) - } - + recover(address, signature, controller) { + return this.registry.recover( + address, + signature.v, + signature.r, + signature.s, + controller, + { + gasLimit: 10000000, + gasPrice: 0, + } + ); + } } diff --git a/lib/resolver.js b/lib/resolver.js index 7124f5e..e122b42 100644 --- a/lib/resolver.js +++ b/lib/resolver.js @@ -1,187 +1,246 @@ import bs58 from "bs58"; import * as ethers from "ethers"; -import DIDRegistryContract from './DIDRegistry.json' +import DIDRegistryContract from "./DIDRegistry.json"; import DIDDocument from "./document.js"; import { bytes32toString, keyAlgorithms, parseDID } from "./utils.js"; import lacchain from "@lacchain/gas-model-provider"; const { BigNumber } = ethers; -export function getVerificationMethod( did, index, algo, encoding, value, controller ) { - const verificationMethod = { - id: `${did}#vm-${index}`, - type: `${keyAlgorithms[algo]}`, - controller - } - switch( encoding ) { - case null: - case undefined: - case 'hex': - verificationMethod.publicKeyHex = value.slice( 2 ) - break - case 'blockchain': - verificationMethod.blockchainAccountId = value; - break - case 'base64': - verificationMethod.publicKeyBase64 = Buffer.from( - value.slice( 2 ), - 'hex' - ).toString( 'base64' ) - break - case 'base58': - verificationMethod.publicKeyBase58 = bs58.encode( Buffer.from( - value.slice( 2 ), - 'hex' - ) ) - break - case 'pem': - verificationMethod.publicKeyPem = Buffer.from( - value.slice( 2 ), - 'hex' - ).toString() - break - case 'json': - verificationMethod.publicKeyJwk = JSON.parse((Buffer.from( value.slice(2), 'hex' )).toString()); - break; - } - return verificationMethod; +export function getVerificationMethod( + did, + index, + algo, + encoding, + value, + controller +) { + const verificationMethod = { + id: `${did}#vm-${index}`, + type: `${keyAlgorithms[algo]}`, + controller, + }; + switch (encoding) { + case null: + case undefined: + case "hex": + verificationMethod.publicKeyHex = value.slice(2); + break; + case "blockchain": + verificationMethod.blockchainAccountId = value; + break; + case "base64": + verificationMethod.publicKeyBase64 = Buffer.from( + value.slice(2), + "hex" + ).toString("base64"); + break; + case "base58": + verificationMethod.publicKeyBase58 = bs58.encode( + Buffer.from(value.slice(2), "hex") + ); + break; + case "pem": + verificationMethod.publicKeyPem = Buffer.from( + value.slice(2), + "hex" + ).toString(); + break; + case "json": + verificationMethod.publicKeyJwk = JSON.parse( + Buffer.from(value.slice(2), "hex").toString() + ); + break; + } + return verificationMethod; } -export function wrapDidDocument( did, id, controller, history, mode ) { - const now = BigNumber.from( Math.floor( new Date().getTime() / 1000 ) ); - const defaultVerificationMethod = [] - - const authentication = [] - - let index = -1 - const relationships = { - auth: {}, - asse: {}, - keya: {}, - dele: {}, - invo: {} - } - const verificationMethods = {} - const services = {} - for( const event of history ) { - const validTo = event.args.validTo; - const key = `${event.name}-${event.args.name}-${event.args.value}` - const value = event.args.value; - if( validTo && validTo.gte( now ) ) { - if( event.name !== 'DIDAttributeChanged' ) continue; - const name = bytes32toString( event.args.name ) - const match = name.match( /(vm|auth|asse|keya|dele|invo|svc)\/(.+)?\/(\w+)?\/(\w+)?$/ ) - if( !match ) continue; - const type = match[1] - const controller = match[2] - const algo = match[3] - const encoding = match[4] - switch( type ) { - case 'vm': - index++ - verificationMethods[key] = getVerificationMethod( did, index, algo, encoding, value, controller ); - break - case 'auth': - case 'asse': - case 'keya': - case 'dele': - case 'invo': - if( !algo && !encoding ) { - relationships[type][key] = Buffer.from( value.slice( 2 ), 'hex' ).toString(); - continue; - } - index++ - verificationMethods[key] = getVerificationMethod( did, index, algo, encoding, value, controller ); - relationships[type][key] = verificationMethods[key].id; - break - case 'svc': - services[key] = { - type: algo, - serviceEndpoint: Buffer.from( event.args.value.slice( 2 ), 'hex' ).toString() - } - break - } - } else { - const name = event.args.name ? bytes32toString( event.args.name ) : event.args.name; - if( index > 0 && - ( event.name === 'DIDAttributeChanged' && - name.match( /(vm|auth|asse|keya|dele|invo|svc)\/(\w+)?\/(\w+)?\/(\w+)?$/ ) ) && - validTo.lt( now ) ) { - index-- - } - delete relationships.auth[key]; - delete relationships.asse[key]; - delete relationships.keya[key]; - delete relationships.dele[key]; - delete relationships.invo[key]; - delete verificationMethods[key] - delete services[key] - } - } - - const doc = { - '@context': ['https://w3id.org/did/v1', 'https://w3id.org/security/suites/jws-2020/v1'], - id: did, - controller, - verificationMethod: defaultVerificationMethod.concat( Object.values( verificationMethods ) ), - authentication: authentication.concat( Object.values( relationships.auth ) ), - assertionMethod: authentication.concat( Object.values( relationships.asse ) ), - keyAgreement: authentication.concat( Object.values( relationships.keya ) ), - capabilityInvocation: authentication.concat( Object.values( relationships.invo ) ), - capabilityDelegation: authentication.concat( Object.values( relationships.dele ) ) - } - if( Object.values( services ).length > 0 ) { - doc.service = Object.values( services ) - } - - return new DIDDocument( doc, mode ); +export function wrapDidDocument(did, controller, history, mode) { + const now = BigNumber.from(Math.floor(new Date().getTime() / 1000)); + const defaultVerificationMethod = []; + + const authentication = []; + + let index = -1; + const relationships = { + auth: {}, + asse: {}, + keya: {}, + dele: {}, + invo: {}, + }; + const verificationMethods = {}; + const services = {}; + + for (const event of history) { + const validTo = event.args.validTo; + const key = `${event.name}-${event.args.name}-${event.args.value}`; + const value = event.args.value; + if (validTo && validTo.gte(now)) { + if (event.name !== "DIDAttributeChanged") continue; + const name = bytes32toString(event.args.name); + const match = name.match( + /(vm|auth|asse|keya|dele|invo|svc)\/(.+)?\/(\w+)?\/(\w+)?$/ + ); + if (!match) continue; + const type = match[1]; + const controller = match[2]; + const algo = match[3]; + const encoding = match[4]; + switch (type) { + case "vm": + index++; + verificationMethods[key] = getVerificationMethod( + did, + index, + algo, + encoding, + value, + controller + ); + break; + case "auth": + case "asse": + case "keya": + case "dele": + case "invo": + if (!algo && !encoding) { + relationships[type][key] = Buffer.from( + value.slice(2), + "hex" + ).toString(); + continue; + } + index++; + verificationMethods[key] = getVerificationMethod( + did, + index, + algo, + encoding, + value, + controller + ); + relationships[type][key] = verificationMethods[key].id; + break; + case "svc": + services[key] = { + type: algo, + serviceEndpoint: Buffer.from( + event.args.value.slice(2), + "hex" + ).toString(), + }; + break; + } + } else { + const name = event.args.name + ? bytes32toString(event.args.name) + : event.args.name; + if ( + index > 0 && + event.name === "DIDAttributeChanged" && + name.match( + /(vm|auth|asse|keya|dele|invo|svc)\/(\w+)?\/(\w+)?\/(\w+)?$/ + ) && + validTo.lt(now) + ) { + index--; + } + delete relationships.auth[key]; + delete relationships.asse[key]; + delete relationships.keya[key]; + delete relationships.dele[key]; + delete relationships.invo[key]; + delete verificationMethods[key]; + delete services[key]; + } + } + + const doc = { + "@context": [ + "https://w3id.org/did/v1", + "https://w3id.org/security/suites/jws-2020/v1", + ], + id: did, + controller, + verificationMethod: defaultVerificationMethod.concat( + Object.values(verificationMethods) + ), + authentication: authentication.concat(Object.values(relationships.auth)), + assertionMethod: authentication.concat(Object.values(relationships.asse)), + keyAgreement: authentication.concat(Object.values(relationships.keya)), + capabilityInvocation: authentication.concat( + Object.values(relationships.invo) + ), + capabilityDelegation: authentication.concat( + Object.values(relationships.dele) + ), + }; + if (Object.values(services).length > 0) { + doc.service = Object.values(services); + } + + return new DIDDocument(doc, mode); } +export function getResolver(config = {}) { + const iface = new ethers.utils.Interface(DIDRegistryContract.abi); + + async function changeLog(identity, registry) { + const history = []; + let previousChange = await registry.changed(identity); + const controller = previousChange + ? await registry.identityController(identity) + : identity; + while (previousChange) { + const blockNumber = previousChange; + const logs = await registry.queryFilter( + { + address: config.registry, + topics: [null, `0x000000000000000000000000${identity.slice(2)}`], + }, + previousChange.toNumber(), + previousChange.toNumber() + ); + previousChange = undefined; + for (const log of logs) { + const event = iface.parseLog(log); + history.unshift({ ...event, hash: log.transactionHash }); + if (event.args.previousChange.lt(blockNumber)) { + previousChange = event.args.previousChange; + } + } + } -export function getResolver( config = {} ) { - const iface = new ethers.utils.Interface( DIDRegistryContract.abi ); - - async function changeLog( identity, registry ) { - const history = [] - let previousChange = await registry.changed( identity ) - const controller = previousChange ? await registry.identityController( identity ) : identity; - while( previousChange ) { - const blockNumber = previousChange - const logs = await registry.queryFilter( { - address: config.registry, - topics: [null, `0x000000000000000000000000${identity.slice( 2 )}`], - }, previousChange.toNumber(), previousChange.toNumber() ) - previousChange = undefined - for( const log of logs ) { - const event = iface.parseLog( log ); - history.unshift( { ...event, hash: log.transactionHash } ) - if( event.args.previousChange.lt( blockNumber ) ) { - previousChange = event.args.previousChange; - } - } - } - return { controller, history } - } - - async function resolve( did ) { - const parsed = parseDID( did ); - const fullId = parsed.id.match( /^(.*)?(0x[0-9a-fA-F]{40})$/ ) - if( !fullId ) throw new Error( `Not a valid ethr DID: ${did}` ) - const id = fullId[2] - - const network = config.networks.find( net => net.name === parsed.network ); - if( !network ) throw new Error( `No config for networkId: ${parsed.network}` ) - - let provider = new ethers.providers.JsonRpcProvider( network.rpcUrl ); - if( network.nodeAddress ) - provider = new lacchain.GasModelProvider( network.rpcUrl ); - const registry = new ethers.Contract( network.registry, DIDRegistryContract.abi, provider ) - - const { controller, history } = await changeLog( id, registry ) - return wrapDidDocument( did, id, - `did:lac:${parsed.network}:${controller.toLowerCase()}`, - history, config.mode ); - } - - return { lac: resolve } -} \ No newline at end of file + return { controller, history }; + } + + async function resolve(did) { + const parsed = parseDID(did); + const fullId = parsed.id.match(/^(.*)?(0x[0-9a-fA-F]{40})$/); + if (!fullId) throw new Error(`Not a valid ethr DID: ${did}`); + const id = fullId[2]; + + const network = config.networks.find((net) => net.name === parsed.network); + if (!network) throw new Error(`No config for networkId: ${parsed.network}`); + + let provider = new ethers.providers.JsonRpcProvider(network.rpcUrl); + if (network.nodeAddress) + provider = new lacchain.GasModelProvider(network.rpcUrl); + const registry = new ethers.Contract( + network.registry, + DIDRegistryContract.abi, + provider + ); + + const { controller, history } = await changeLog(id, registry); + return wrapDidDocument( + did, + `did:lac:${parsed.network}:${controller.toLowerCase()}`, + history, + config.mode + ); + } + + return { lac: resolve }; +} diff --git a/package-lock.json b/package-lock.json index ee5efcd..2305a9e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@lacchain/did", - "version": "1.4.8", + "version": "1.6.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@lacchain/did", - "version": "1.4.8", + "version": "1.6.3", "license": "Apache-2.0", "dependencies": { "@lacchain/gas-model-provider": "^1.1.0", diff --git a/package.json b/package.json index 7491a53..d53bb80 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lacchain/did", - "version": "1.6.3", + "version": "1.7.0", "description": "The LACChain DID Method NodeJS Implementation", "author": "Sergio Ceron Figueroa ", "keywords": [ @@ -16,7 +16,7 @@ "homepage": "http://dev.lacchain.net/en/did-method", "type": "module", "scripts": { - "test": "./node_modules/mocha/bin/mocha --experimental-json-modules --timeout 30000 --ui bdd ./test/**", + "test": "./node_modules/mocha/bin/mocha --experimental-json-modules --timeout 50000 --ui bdd ./test/**", "coverage": "nyc mocha --experimental-json-modules --experimental-loader=@istanbuljs/esm-loader-hook --timeout 30000 --ui bdd ./test/**", "report-coverage": "nyc report --reporter=text-lcov > coverage.lcov" }, diff --git a/test/did.js b/test/lac/did.js similarity index 97% rename from test/did.js rename to test/lac/did.js index acfaaae..cbb75a7 100644 --- a/test/did.js +++ b/test/lac/did.js @@ -1,7 +1,7 @@ import chai from "chai"; import chaiAsPromised from "chai-as-promised"; -import DID from "../lib/did.js"; -import { createKeyPair, sleep } from "../lib/utils.js"; +import DID from "../../lib/did.js"; +import { createKeyPair, sleep } from "../../lib/utils.js"; import { failToCreateWithoutAddress, shouldAddAssertionMethod, @@ -25,7 +25,7 @@ import { shouldGetDidDocumentReferenceMode, shouldRemoveLastDidController, } from "./lacBaseTestMethods.js"; -import { getLacDidTestParams } from "./testInitializer.js"; +import { getLacDidTestParams } from "../testInitializer.js"; const expect = chai.expect; chai.use(chaiAsPromised); @@ -34,7 +34,7 @@ chai.should(); const { registry, nodeAddress, rpcUrl, network, expiration } = await getLacDidTestParams(); -describe("DID", () => { +describe("LAC DID", () => { const newDid = async () => { return new DID({ registry, diff --git a/test/lacBaseTestMethods.js b/test/lac/lacBaseTestMethods.js similarity index 97% rename from test/lacBaseTestMethods.js rename to test/lac/lacBaseTestMethods.js index 0262d19..ad77bdc 100644 --- a/test/lacBaseTestMethods.js +++ b/test/lac/lacBaseTestMethods.js @@ -1,14 +1,14 @@ import chai from "chai"; import bs58 from "bs58"; import chaiAsPromised from "chai-as-promised"; -import { createKeyPair, sleep } from "../lib/utils.js"; -import DIDLac1 from "../lib/lac1/lac1Did.js"; +import { createKeyPair, sleep } from "../../lib/utils.js"; +import DIDLac1 from "../../lib/lac1/lac1Did.js"; const expect = chai.expect; chai.use(chaiAsPromised); chai.should(); -const registry = "0xb4FB2e9BB0001cc8eAAE528571915F35Cb74C864"; // "0x6711Ed022C51fB5082cf8Ac6D51c45A03796b8d1"; +const registry = "0xb4FB2e9BB0001cc8eAAE528571915F35Cb74C864"; const nodeAddress = "0xad730de8c4bfc3d845f7ce851bcf2ea17c049585"; const rpcUrl = "http://35.185.112.219"; const network = "openprotest"; @@ -99,7 +99,6 @@ const shouldAddVerificationMethod = async (did) => { const document = await did.getDocument(); expect(document.verificationMethod).to.not.be.null; - // expect(document.verificationMethod).to.have.lengthOf(2); // TODO: Verify why this is not accomplished expect(document.verificationMethod[0].publicKeyHex).to.equal( veryKey.publicKey ); diff --git a/test/lac/recover.js b/test/lac/recover.js new file mode 100644 index 0000000..11a8f9d --- /dev/null +++ b/test/lac/recover.js @@ -0,0 +1,74 @@ +import chai from "chai"; +import chaiAsPromised from "chai-as-promised"; +import DIDRecoverable from "../../lib/didrecoverable.js"; +import { createKeyPair, sleep } from "../../lib/utils.js"; + +const expect = chai.expect; +chai.use(chaiAsPromised); +chai.should(); + +// TODO: Add similar tests for lac1 DID method +describe("LAC DIDRecoverable", () => { + const did = new DIDRecoverable({ + registry: "0x21D8dB083E0515EB2c8918CD49ea56C5B900ecef", + rpcUrl: "https://writer.lacchain.net", + network: "main", + }); + + const controller1 = createKeyPair(); + const controller2 = createKeyPair(); + const controller3 = createKeyPair(); + const controller4 = createKeyPair(); + + before(async () => { + await did.addController(controller1.address); + await did.addController(controller2.address); + await did.addController(controller3.address); + }); + + it("should not have the minimum keys", async () => { + try { + await did.recover(controller1.address, controller1.privateKey); + } catch (e) { + expect(e.reason).to.equal("transaction failed"); + } + }); + + it("should fail the recover signature", async () => { + await did.addController(controller4.address); + try { + await did.recover(controller1.address, controller2.privateKey); + } catch (e) { + expect(e.reason).to.equal("transaction failed"); + } + }); + + it("should exceed failed attempts", async () => { + try { + for (const _ of [0, 1, 2, 3, 4]) { + await did.recover(controller1.address, controller1.privateKey); + } + } catch (e) { + expect(e.reason).to.equal("transaction failed"); + } + }); + + it("should pass max attempts by waiting reset time", async () => { + await sleep(10); + await did.recover(controller1.address, controller1.privateKey); + }); + + it("should recover key successfully", async () => { + await sleep(10); + const controller = await did.getController(); + await did.recover(controller2.address, controller2.privateKey); + await did.recover(controller3.address, controller3.privateKey); + await did.recover(controller4.address, controller4.privateKey); + const recoveredController = await did.getController(); + + expect(controller).to.not.be.equal(recoveredController); + expect(recoveredController.toLowerCase()).to.equal( + controller4.address.toLowerCase() + ); + }); +}); diff --git a/test/lac1Resolver.js b/test/lac/resolver.js similarity index 55% rename from test/lac1Resolver.js rename to test/lac/resolver.js index fa4c57b..06cde9f 100644 --- a/test/lac1Resolver.js +++ b/test/lac/resolver.js @@ -1,41 +1,36 @@ import chai from "chai"; import chaiAsPromised from "chai-as-promised"; -import { getResolver } from "../lib/lac1/resolver.js"; -import { - getLac1didTestParams, - newLac1Did as newDid, -} from "./testInitializer.js"; +import { getResolver } from "../../lib/resolver.js"; const expect = chai.expect; chai.use(chaiAsPromised); chai.should(); -describe("Lac1DIDResolver", async () => { - const { registry, nodeAddress, rpcUrl, chainId } = - await getLac1didTestParams(); +describe("LAC DIDResolver", () => { + const did = "did:lac:omega:0xcd7ebd413d512b47d1d48e5ed27fe01c8c29fd98"; const invalid = "dsid:lac:axcd7ebd413d512b47d1d48e5ed27fe01c8c29fd98"; const resolver = getResolver({ networks: [ { - registry, - rpcUrl, - nodeAddress, - chainId, + name: "omega", + registry: "0xde82d4Cea1242C04B6baF6f98095F6050c88f50b", + rpcUrl: "http://34.73.228.200", + nodeAddress: "0x971bb94d235a4ba42d53ab6fb0a86b12c73ba460", + expiration: "1736394529", }, ], // mode: 'explicit' }); it("should resolve the DID Document", async () => { - const did = await newDid(); - const document = await resolver.lac1(did.id); + const document = await resolver.lac(did); expect(document).to.be.not.null; }); it("should fail to resolve the Document of an invalid DID", async () => { try { - await resolver.lac1(invalid); + await resolver.lac(invalid); } catch (e) { expect(e.message).to.equals("Invalid DID"); } diff --git a/test/lac1/lac1BaseTestMethods.js b/test/lac1/lac1BaseTestMethods.js new file mode 100644 index 0000000..974dfd6 --- /dev/null +++ b/test/lac1/lac1BaseTestMethods.js @@ -0,0 +1,345 @@ +import chai from "chai"; +import bs58 from "bs58"; +import chaiAsPromised from "chai-as-promised"; +import { createKeyPair, sleep } from "../../lib/utils.js"; +import { processVerificationMethodIdForAttribute } from "../../lib/lac1/lac1resolverUtils.js"; + +const expect = chai.expect; +chai.use(chaiAsPromised); +chai.should(); + +const shouldAddVerificationMethod = async (did) => { + const veryKey = createKeyPair(); + await did.addVerificationMethod({ + type: "vm", + algorithm: "esecp256k1rm", + encoding: "hex", + publicKey: `0x${veryKey.publicKey}`, + controller: did.address, + }); + const document = await did.getDocument(); + + expect(document.verificationMethod).to.not.be.null; + expect(document.verificationMethod).to.have.lengthOf(2); // TODO: Verify why this is not accomplished + expect(document.verificationMethod[1].publicKeyHex).to.equal( + veryKey.publicKey + ); +}; + +const shouldAddAuthenticationMethod = async (did) => { + const authKey = createKeyPair(); + await did.addAuthenticationMethod({ + algorithm: "esecp256k1rm", + encoding: "hex", + publicKey: `0x${authKey.publicKey}`, + controller: did.address, + }); + const document = await did.getDocument(); + + expect(document.verificationMethod).to.have.lengthOf(2); + expect(document.verificationMethod[1].publicKeyHex).to.equal( + authKey.publicKey + ); + expect(document.authentication).to.not.be.null; + expect(document.authentication).to.have.lengthOf(2); + expect(document.authentication[1].publicKeyHex).to.equal(authKey.publicKey); +}; + +const shouldBindAuthenticationMethod = async (did) => { + const veryKey = createKeyPair(); + const authKey = createKeyPair(); + await did.addVerificationMethod({ + type: "vm", + algorithm: "esecp256k1rm", + encoding: "hex", + publicKey: `0x${veryKey.publicKey}`, + controller: did.id, + }); + await did.addAuthenticationMethod({ + algorithm: "esecp256k1rm", + encoding: "hex", + publicKey: `0x${authKey.publicKey}`, + controller: did.id, + }); + let document = await did.getDocument(); + + const vmId = processVerificationMethodIdForAttribute( + did.id, + veryKey.publicKey + ); + await did.bindAuthenticationMethod(`${did.id}#${vmId}`); + document = await did.getDocument(); + expect(document.verificationMethod).to.have.lengthOf(3); + + expect(document.authentication).to.not.be.null; + expect(document.authentication).to.have.lengthOf(3); + + expect(document.authentication[2].publicKeyHex).to.equal(veryKey.publicKey); // last added -> last listed in array +}; + +const shouldAddAssertionMethod = async (did) => { + const asseKey = createKeyPair(); + const publicKeyBase64 = Buffer.from(asseKey.publicKey, "hex").toString( + "base64" + ); + await did.addAssertionMethod({ + algorithm: "esecp256k1vk", + encoding: "base64", + publicKey: publicKeyBase64, + controller: did.address, + }); + const document = await did.getDocument(); + + expect(document.verificationMethod).to.have.lengthOf(2); + expect(document.verificationMethod[1].publicKeyBase64).to.equal( + publicKeyBase64 + ); + + expect(document.assertionMethod).to.not.be.null; + expect(document.assertionMethod).to.have.lengthOf(2); + expect(document.assertionMethod[1].publicKeyBase64).to.equal(publicKeyBase64); +}; + +const shouldBindAssertionMethod = async (did) => { + const veryKey = createKeyPair(); + const asseKey = createKeyPair(); + await did.addVerificationMethod({ + type: "vm", + algorithm: "esecp256k1rm", + encoding: "hex", + publicKey: `0x${veryKey.publicKey}`, + controller: did.id, + }); + + const publicKeyBase64 = Buffer.from(asseKey.publicKey, "hex").toString( + "base64" + ); + + await did.addAssertionMethod({ + algorithm: "esecp256k1vk", + encoding: "base64", + publicKey: publicKeyBase64, + controller: did.id, + }); + + const vmId = processVerificationMethodIdForAttribute( + did.id, + veryKey.publicKey + ); + + await did.bindAssertionMethod(`${did.id}#${vmId}`); + const document = await did.getDocument(); + + expect(document.verificationMethod).to.have.lengthOf(3); + + expect(document.assertionMethod).to.not.be.null; + expect(document.assertionMethod).to.have.lengthOf(3); + expect(document.assertionMethod[2].publicKeyHex).to.equal(veryKey.publicKey); +}; + +const shouldAddKeyAgreement = async (did) => { + const keyaKey = createKeyPair(); + const publicKeyBase58 = bs58.encode(Buffer.from(keyaKey.publicKey, "hex")); + await did.addKeyAgreement({ + algorithm: "esecp256k1vk", + encoding: "base58", + publicKey: publicKeyBase58, + controller: did.address, + }); + const document = await did.getDocument(); + + expect(document.verificationMethod).to.have.lengthOf(2); + expect(document.verificationMethod[1].publicKeyBase58).to.equal( + publicKeyBase58 + ); + + expect(document.keyAgreement).to.not.be.null; + expect(document.keyAgreement).to.have.lengthOf(1); + expect(document.keyAgreement[0].publicKeyBase58).to.equal(publicKeyBase58); +}; + +const shouldBindKeyAgreement = async (did) => { + const veryKey = createKeyPair(); + const keyaKey = createKeyPair(); + + await did.addVerificationMethod({ + type: "vm", + algorithm: "esecp256k1rm", + encoding: "hex", + publicKey: `0x${veryKey.publicKey}`, + controller: did.id, + }); + + const publicKeyBase58 = bs58.encode(Buffer.from(keyaKey.publicKey, "hex")); + await did.addKeyAgreement({ + algorithm: "esecp256k1vk", + encoding: "base58", + publicKey: publicKeyBase58, + controller: did.id, + }); + + const vmId = processVerificationMethodIdForAttribute( + did.id, + veryKey.publicKey + ); + + await did.bindKeyAgreement(`${did.id}#${vmId}`); + const document = await did.getDocument(); + + expect(document.verificationMethod).to.have.lengthOf(3); + + expect(document.keyAgreement).to.not.be.null; + expect(document.keyAgreement).to.have.lengthOf(2); + expect(document.keyAgreement[1].publicKeyHex).to.equal(veryKey.publicKey); +}; + +const shouldAddCapabilityInvocation = async (did) => { + const veryKey = createKeyPair(); + const invoKey = createKeyPair(); + await did.addVerificationMethod({ + type: "vm", + algorithm: "esecp256k1rm", + encoding: "hex", + publicKey: `0x${veryKey.publicKey}`, + controller: did.id, + }); + + await did.addCapabilityInvocation({ + algorithm: "esecp256k1vk", + encoding: "hex", + publicKey: `0x${invoKey.publicKey}`, + controller: did.id, + }); + const document = await did.getDocument(); + + expect(document.verificationMethod).to.have.lengthOf(3); + expect(document.verificationMethod[2].publicKeyHex).to.equal( + invoKey.publicKey + ); + + expect(document.capabilityInvocation).to.not.be.null; + expect(document.capabilityInvocation).to.have.lengthOf(1); + expect(document.capabilityInvocation[0].publicKeyHex).to.equal( + invoKey.publicKey + ); +}; + +const shouldBindCapabilityInvocation = async (did) => { + const veryKey = createKeyPair(); + const invoKey = createKeyPair(); + await did.addVerificationMethod({ + type: "vm", + algorithm: "esecp256k1rm", + encoding: "hex", + publicKey: `0x${veryKey.publicKey}`, + controller: did.id, + }); + + await did.addCapabilityInvocation({ + algorithm: "esecp256k1vk", + encoding: "hex", + publicKey: `0x${invoKey.publicKey}`, + controller: did.id, + }); + + const vmId = processVerificationMethodIdForAttribute( + did.id, + veryKey.publicKey + ); + + await did.bindCapabilityInvocation(`${did.id}#${vmId}`); + const document = await did.getDocument(); + + expect(document.verificationMethod).to.have.lengthOf(3); + + expect(document.capabilityInvocation).to.not.be.null; + expect(document.capabilityInvocation).to.have.lengthOf(2); + expect(document.capabilityInvocation[1].publicKeyHex).to.equal( + veryKey.publicKey + ); +}; + +const shouldAddCapabilityDelegation = async (did) => { + const deleKey = createKeyPair(); + await did.addCapabilityDelegation({ + algorithm: "esecp256k1vk", + encoding: "pem", + publicKey: deleKey.publicKey, + controller: did.id, + }); + const document = await did.getDocument(); + + expect(document.verificationMethod).to.have.lengthOf(2); + expect(document.verificationMethod[1].publicKeyPem).to.equal( + deleKey.publicKey + ); + + expect(document.capabilityDelegation).to.not.be.null; + expect(document.capabilityDelegation).to.have.lengthOf(1); + expect(document.capabilityDelegation[0].publicKeyPem).to.equal( + deleKey.publicKey + ); +}; + +const shouldBindCapabilityDelegation = async (did) => { + const veryKey = createKeyPair(); + const deleKey = createKeyPair(); + await did.addVerificationMethod({ + type: "vm", + algorithm: "esecp256k1rm", + encoding: "hex", + publicKey: `0x${veryKey.publicKey}`, + controller: did.id, + }); + + const deleId = processVerificationMethodIdForAttribute( + did.id, + veryKey.publicKey + ); + + await did.addCapabilityDelegation({ + algorithm: "esecp256k1vk", + encoding: "pem", + publicKey: deleKey.publicKey, + controller: did.id, + }); + + await did.bindCapabilityDelegation(`${did.id}#${deleId}`); + const document = await did.getDocument(); + + expect(document.verificationMethod).to.have.lengthOf(3); + + expect(document.capabilityDelegation).to.not.be.null; + expect(document.capabilityDelegation).to.have.lengthOf(2); + expect(document.capabilityDelegation[1].publicKeyHex).to.equal( + veryKey.publicKey + ); +}; + +const shouldAddAKAId = async (did, id, validity) => { + await did.addAKAId(id, validity); + const document = await did.getDocument(); + expect(document.toJSON().alsoKnownAs).to.not.be.undefined; +}; + +const shouldRemoveAKAId = async (did, id) => { + await did.removeAKAId(id); + const document = await did.getDocument(); + expect(document.toJSON().alsoKnownAs).to.be.undefined; +}; + +export { + shouldAddVerificationMethod, + shouldAddAuthenticationMethod, + shouldBindAuthenticationMethod, + shouldAddAssertionMethod, + shouldBindAssertionMethod, + shouldAddKeyAgreement, + shouldBindKeyAgreement, + shouldAddCapabilityInvocation, + shouldBindCapabilityInvocation, + shouldAddCapabilityDelegation, + shouldBindCapabilityDelegation, + shouldAddAKAId, + shouldRemoveAKAId, +}; diff --git a/test/lac1Did.js b/test/lac1/lac1Did.js similarity index 83% rename from test/lac1Did.js rename to test/lac1/lac1Did.js index 36a6190..a569840 100644 --- a/test/lac1Did.js +++ b/test/lac1/lac1Did.js @@ -1,22 +1,11 @@ import chai from "chai"; import chaiAsPromised from "chai-as-promised"; -import { createKeyPair, sleep } from "../lib/utils.js"; -import DIDLac1 from "../lib/lac1/lac1Did.js"; +import { createKeyPair, sleep } from "../../lib/utils.js"; +import DIDLac1 from "../../lib/lac1/lac1Did.js"; import { failToCreateWithoutAddress, - shouldAddAssertionMethod, - shouldAddAuthenticationMethod, - shouldAddCapabilityDelegation, - shouldAddCapabilityInvocation, shouldAddDidController, - shouldAddKeyAgreement, shouldAddService, - shouldAddVerificationMethod, - shouldBindAssertionMethod, - shouldBindAuthenticationMethod, - shouldBindCapabilityDelegation, - shouldBindCapabilityInvocation, - shouldBindKeyAgreement, shouldChangeDidController, shouldChangeDidControllerWithSignedTx, shouldFailToChangeDidController, @@ -24,20 +13,36 @@ import { shouldGetDidDocumentExplicitMode, shouldGetDidDocumentReferenceMode, shouldRemoveLastDidController, -} from "./lacBaseTestMethods.js"; +} from "../lac/lacBaseTestMethods.js"; + +import { + shouldAddVerificationMethod, + shouldAddAuthenticationMethod, + shouldBindAuthenticationMethod, + shouldAddAssertionMethod, + shouldBindAssertionMethod, + shouldAddKeyAgreement, + shouldBindKeyAgreement, + shouldAddCapabilityInvocation, + shouldBindCapabilityInvocation, + shouldAddCapabilityDelegation, + shouldBindCapabilityDelegation, + shouldAddAKAId, + shouldRemoveAKAId, +} from "./lac1BaseTestMethods.js"; import { getLac1didTestParams, newLac1Did as newDid, -} from "./testInitializer.js"; +} from "../testInitializer.js"; const expect = chai.expect; chai.use(chaiAsPromised); chai.should(); -const { registry, nodeAddress, rpcUrl, network, expiration } = +const { registry, nodeAddress, rpcUrl, network, expiration, chainId } = await getLac1didTestParams(); -describe("DIDLac1", async () => { +describe("LAC1 DID", async () => { const veryKey = createKeyPair(); it("should fail to create a DID without address", async () => { @@ -145,7 +150,7 @@ describe("DIDLac1", async () => { algorithm: "esecp256k1rm", encoding: "hex", publicKey: `0x${veryKey.publicKey}`, - controller: did.address, + controller: did.id, }); await did.revokeVerificationMethod({ @@ -153,13 +158,13 @@ describe("DIDLac1", async () => { algorithm: "esecp256k1rm", encoding: "hex", publicKey: `0x${veryKey.publicKey}`, - controller: did.address, + controller: did.id, revokeDeltaTimeSeconds: 86400, // e.g. 86400: 1 day before compromised: false, // the key is being rotated (not compomised) }); const document = await did.getDocument(); - expect(document.verificationMethod).to.have.lengthOf(0); + expect(document.verificationMethod).to.have.lengthOf(1); }); it("should add a Service", async () => { @@ -176,4 +181,19 @@ describe("DIDLac1", async () => { const did = await newDid(); await shouldGetDidDocumentReferenceMode(did); }); + + it("Should add an AKA Identifier to a DID", async () => { + const did = await newDid(); + const someId = "id:123"; + const validity = 86400 * 365; + await shouldAddAKAId(did, someId, validity); + }); + + it("Should remove an AKA Identifier to a DID", async () => { + const did = await newDid(); + const someId = "id:123"; + const validity = 86400 * 365; + await shouldAddAKAId(did, someId, validity); + await shouldRemoveAKAId(did, someId); + }); }); diff --git a/test/lac1/lac1Resolver.js b/test/lac1/lac1Resolver.js new file mode 100644 index 0000000..d2cdcf2 --- /dev/null +++ b/test/lac1/lac1Resolver.js @@ -0,0 +1,62 @@ +import chai from "chai"; + +import chaiAsPromised from "chai-as-promised"; +import { getResolver } from "../../lib/lac1/resolver.js"; +import { + getLac1didTestParams, + newLac1Did as newDid, +} from "../testInitializer.js"; +import { processVerificationMethodIdForAttribute } from "../../lib/lac1/lac1resolverUtils.js"; + +const expect = chai.expect; +chai.use(chaiAsPromised); +chai.should(); + +describe("Lac1 DIDResolver", async () => { + const { registry, nodeAddress, rpcUrl, chainId } = + await getLac1didTestParams(); + const invalid = "dsid:lac:axcd7ebd413d512b47d1d48e5ed27fe01c8c29fd98"; + const resolver = getResolver({ + networks: [ + { + registry, + rpcUrl, + nodeAddress, + chainId, + }, + ], + // mode: 'explicit' + }); + + it("should resolve the DID Document", async () => { + const did = await newDid(); + const document = await resolver.lac1(did.id); + expect(document).to.be.not.null; + }); + + it("should fail to resolve the Document of an invalid DID", async () => { + try { + await resolver.lac1(invalid); + } catch (e) { + expect(e.message).to.equals("Invalid DID"); + } + }); + it("Should set current DID Controller as the default verification method with authentication relationship", async () => { + const did = await newDid(); + const document = await resolver.lac1(did.id); + const d = document.verificationMethod[0]; + expect(d["controller"]).to.eq(did.id); + const currentController = await did.getController(); + const defaultIdVerificationMethod = processVerificationMethodIdForAttribute( + did.id, + currentController + ); + expect(d["id"]).to.eq(`${did.id}#${defaultIdVerificationMethod}`); + expect(d["type"]).to.eq("EcdsaSecp256k1RecoveryMethod2020"); + const retrievedHexchainId = + did.chainId.length % 2 == 0 ? did.chainId : "0" + did.chainId; + const retrievedIntchainId = parseInt(retrievedHexchainId, 16); + const blockchainAccountId = `eip155:${retrievedIntchainId}:${currentController}`; + expect(d["blockchainAccountId"]).to.eq(blockchainAccountId); + }); +}); diff --git a/test/recover.js b/test/recover.js deleted file mode 100644 index b1e9149..0000000 --- a/test/recover.js +++ /dev/null @@ -1,71 +0,0 @@ -import chai from 'chai'; -import chaiAsPromised from "chai-as-promised"; -import DIDRecoverable from "../lib/didrecoverable.js"; -import { createKeyPair, sleep } from "../lib/utils.js"; - -const expect = chai.expect; -chai.use( chaiAsPromised ); -chai.should(); - -describe( 'DIDRecoverable', () => { - const did = new DIDRecoverable( { - registry: '0x21D8dB083E0515EB2c8918CD49ea56C5B900ecef', - rpcUrl: 'https://writer.lacchain.net', - network: 'main' - } ); - - const controller1 = createKeyPair(); - const controller2 = createKeyPair(); - const controller3 = createKeyPair(); - const controller4 = createKeyPair(); - - before( async() => { - await did.addController( controller1.address ); - await did.addController( controller2.address ); - await did.addController( controller3.address ); - } ) - - it( "should not have the minimum keys", async() => { - try { - await did.recover( controller1.address, controller1.privateKey ); - } catch( e ) { - expect( e.reason ).to.equal( "transaction failed" ) - } - } ); - - it( "should fail the recover signature", async() => { - await did.addController( controller4.address ); - try { - await did.recover( controller1.address, controller2.privateKey ); - } catch( e ) { - expect( e.reason ).to.equal( "transaction failed" ) - } - } ); - - it( "should exceed failed attempts", async() => { - try { - for( const _ of [0, 1, 2, 3, 4] ) { - await did.recover( controller1.address, controller1.privateKey ); - } - } catch( e ) { - expect( e.reason ).to.equal( "transaction failed" ); - } - } ); - - it( "should pass max attempts by waiting reset time", async() => { - await sleep( 10 ); - await did.recover( controller1.address, controller1.privateKey ); - } ); - - it( "should recover key successfully", async() => { - await sleep( 10 ); - const controller = await did.getController(); - await did.recover( controller2.address, controller2.privateKey ); - await did.recover( controller3.address, controller3.privateKey ); - await did.recover( controller4.address, controller4.privateKey ); - const recoveredController = await did.getController(); - - expect( controller ).to.not.be.equal( recoveredController ); - expect( recoveredController.toLowerCase() ).to.equal( controller4.address.toLowerCase() ); - } ); -} ); \ No newline at end of file diff --git a/test/resolver.js b/test/resolver.js deleted file mode 100644 index 300db54..0000000 --- a/test/resolver.js +++ /dev/null @@ -1,37 +0,0 @@ -import chai from 'chai'; - -import chaiAsPromised from "chai-as-promised"; -import { getResolver } from "../lib/resolver.js"; - -const expect = chai.expect; -chai.use( chaiAsPromised ); -chai.should(); - -describe( 'DIDResolver', () => { - const did = 'did:lac:omega:0xcd7ebd413d512b47d1d48e5ed27fe01c8c29fd98'; - const invalid = 'dsid:lac:axcd7ebd413d512b47d1d48e5ed27fe01c8c29fd98'; - const resolver = getResolver( { - networks: [{ - name: 'omega', - registry: '0xde82d4Cea1242C04B6baF6f98095F6050c88f50b', - rpcUrl: 'http://34.73.228.200', - nodeAddress: '0x971bb94d235a4ba42d53ab6fb0a86b12c73ba460', - expiration: '1736394529', - }] - // mode: 'explicit' - } ); - - it( 'should resolve the DID Document', async() => { - const document = await resolver.lac( did ); - expect( document ).to.be.not.null; - } ); - - it( 'should fail to resolve the Document of an invalid DID', async() => { - try { - await resolver.lac( invalid ); - } catch( e ) { - expect( e.message ).to.equals( 'Invalid DID' ); - } - } ); - -} ); \ No newline at end of file diff --git a/test/testInitializer.js b/test/testInitializer.js index 0eab953..19df341 100644 --- a/test/testInitializer.js +++ b/test/testInitializer.js @@ -1,6 +1,6 @@ import DIDLac1 from "../lib/lac1/lac1Did.js"; -const lac1Registry = "0xb4FB2e9BB0001cc8eAAE528571915F35Cb74C864"; +const lac1Registry = "0xd2d7bF1A9a774f09cbA9541c5326B22f83f734Df"; const nodeAddress = "0xad730de8c4bfc3d845f7ce851bcf2ea17c049585"; const rpcUrl = "http://35.185.112.219"; const network = "openprotest";