From cb3edab61f6e070f14a16b304bb6232aec0e5057 Mon Sep 17 00:00:00 2001 From: Dylan Moreland Date: Thu, 20 Jul 2023 22:10:55 -0400 Subject: [PATCH 01/11] Flip around the primary key, make vehicle nullable Import new contract version --- internal/contracts/registry.go | 56 +++- .../synthetic_devices_controller.go | 3 +- .../synthetic_devices_controller_test.go | 4 +- internal/services/registry/storage_test.go | 6 +- .../20230720215147_synthetic_multi_mint.sql | 14 + models/external_vin_data.go | 228 ++++++++++++++- models/meta_transaction_requests.go | 4 +- models/synthetic_devices.go | 71 +++-- models/user_devices.go | 265 ++++++++++++++++++ models/vehicle_nfts.go | 76 ++++- 10 files changed, 696 insertions(+), 31 deletions(-) create mode 100644 migrations/20230720215147_synthetic_multi_mint.sql diff --git a/internal/contracts/registry.go b/internal/contracts/registry.go index 1ee1c3005..38c47c05a 100644 --- a/internal/contracts/registry.go +++ b/internal/contracts/registry.go @@ -70,9 +70,21 @@ type MintSyntheticDeviceInput struct { AttrInfoPairs []AttributeInfoPair } +// MintVehicleAndSdInput is an auto generated low-level Go binding around an user-defined struct. +type MintVehicleAndSdInput struct { + ManufacturerNode *big.Int + Owner common.Address + AttrInfoPairsVehicle []AttributeInfoPair + IntegrationNode *big.Int + VehicleOwnerSig []byte + SyntheticDeviceSig []byte + SyntheticDeviceAddr common.Address + AttrInfoPairsDevice []AttributeInfoPair +} + // RegistryMetaData contains all meta data concerning the Registry contract. var RegistryMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"UintUtils__InsufficientHexLength\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"moduleAddr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4[]\",\"name\":\"selectors\",\"type\":\"bytes4[]\"}],\"name\":\"ModuleAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"moduleAddr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4[]\",\"name\":\"selectors\",\"type\":\"bytes4[]\"}],\"name\":\"ModuleRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldImplementation\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4[]\",\"name\":\"oldSelectors\",\"type\":\"bytes4[]\"},{\"indexed\":false,\"internalType\":\"bytes4[]\",\"name\":\"newSelectors\",\"type\":\"bytes4[]\"}],\"name\":\"ModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"},{\"internalType\":\"bytes4[]\",\"name\":\"selectors\",\"type\":\"bytes4[]\"}],\"name\":\"addModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"},{\"internalType\":\"bytes4[]\",\"name\":\"selectors\",\"type\":\"bytes4[]\"}],\"name\":\"removeModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"oldImplementation\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes4[]\",\"name\":\"oldSelectors\",\"type\":\"bytes4[]\"},{\"internalType\":\"bytes4[]\",\"name\":\"newSelectors\",\"type\":\"bytes4[]\"}],\"name\":\"updateModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceTransferredDevAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"}],\"name\":\"AftermarketDeviceUnclaimedDevAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceUnpairedDevAdmin\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"internalType\":\"structDevAdmin.IdManufacturerName[]\",\"name\":\"idManufacturerNames\",\"type\":\"tuple[]\"}],\"name\":\"renameManufacturers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferAftermarketDeviceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"aftermarketDeviceNodes\",\"type\":\"uint256[]\"}],\"name\":\"unclaimAftermarketDeviceNode\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"aftermarketDeviceNodes\",\"type\":\"uint256[]\"}],\"name\":\"unpairAftermarketDeviceByDeviceNode\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"vehicleNodes\",\"type\":\"uint256[]\"}],\"name\":\"unpairAftermarketDeviceByVehicleNode\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"version\",\"type\":\"string\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multiDelegateCall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multiStaticCall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdMintCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"adMintCost\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_adMintCost\",\"type\":\"uint256\"}],\"name\":\"setAdMintCost\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_dimoToken\",\"type\":\"address\"}],\"name\":\"setDimoToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_foundation\",\"type\":\"address\"}],\"name\":\"setFoundationAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_license\",\"type\":\"address\"}],\"name\":\"setLicense\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"AdNotClaimed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"AdNotPaired\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"AdPaired\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attr\",\"type\":\"string\"}],\"name\":\"AttributeExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attr\",\"type\":\"string\"}],\"name\":\"AttributeNotWhitelisted\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"DeviceAlreadyClaimed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"DeviceAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAdSignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidLicense\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"InvalidNode\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidOwnerSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"InvalidParentNode\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OwnersDoesNotMatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryNotApproved\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"VehicleNotPaired\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"VehiclePaired\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"AftermarketDeviceAttributeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"AftermarketDeviceAttributeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceIdProxySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"manufacturerId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"aftermarketDeviceAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceNodeMinted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"AftermarketDevicePaired\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceUnpaired\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"addAftermarketDeviceAttribute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerNode\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNodeId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"internalType\":\"structAftermarketDeviceOwnerPair[]\",\"name\":\"adOwnerPair\",\"type\":\"tuple[]\"}],\"name\":\"claimAftermarketDeviceBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"ownerSig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"aftermarketDeviceSig\",\"type\":\"bytes\"}],\"name\":\"claimAftermarketDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getAftermarketDeviceIdByAddress\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerNode\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairs\",\"type\":\"tuple[]\"}],\"internalType\":\"structAftermarketDeviceInfos[]\",\"name\":\"adInfos\",\"type\":\"tuple[]\"}],\"name\":\"mintAftermarketDeviceByManufacturerBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"aftermarketDeviceSig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"vehicleOwnerSig\",\"type\":\"bytes\"}],\"name\":\"pairAftermarketDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"pairAftermarketDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setAftermarketDeviceIdProxyAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfo\",\"type\":\"tuple[]\"}],\"name\":\"setAftermarketDeviceInfo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"unpairAftermarketDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"controller\",\"type\":\"address\"}],\"name\":\"ControllerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"ManufacturerAttributeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"ManufacturerAttributeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"ManufacturerIdProxySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"ManufacturerNodeMinted\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"addManufacturerAttribute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"getManufacturerIdByName\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getManufacturerNameById\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isAllowedToOwnManufacturerNode\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isAllowed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isController\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isController\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isManufacturerMinted\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isManufacturerMinted\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairList\",\"type\":\"tuple[]\"}],\"name\":\"mintManufacturer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string[]\",\"name\":\"names\",\"type\":\"string[]\"}],\"name\":\"mintManufacturerBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_controller\",\"type\":\"address\"}],\"name\":\"setController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setManufacturerIdProxyAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoList\",\"type\":\"tuple[]\"}],\"name\":\"setManufacturerInfo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"updateManufacturerMinted\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"AlreadyController\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"IntegrationNameRegisterd\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"MustBeAdmin\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"NotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyNftProxy\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"IntegrationAttributeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"IntegrationAttributeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"IntegrationIdProxySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"IntegrationNodeMinted\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"addIntegrationAttribute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"getIntegrationIdByName\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getIntegrationNameById\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isAllowedToOwnIntegrationNode\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isAllowed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isIntegrationController\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isController\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isIntegrationMinted\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isIntegrationMinted\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairList\",\"type\":\"tuple[]\"}],\"name\":\"mintIntegration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string[]\",\"name\":\"names\",\"type\":\"string[]\"}],\"name\":\"mintIntegrationBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_controller\",\"type\":\"address\"}],\"name\":\"setIntegrationController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setIntegrationIdProxyAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoList\",\"type\":\"tuple[]\"}],\"name\":\"setIntegrationInfo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"updateIntegrationMinted\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"InvalidSdSignature\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"SyntheticDeviceAttributeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"SyntheticDeviceAttributeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"SyntheticDeviceIdProxySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"syntheticDeviceNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SyntheticDeviceNodeBurned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"integrationNode\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"syntheticDeviceNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"syntheticDeviceAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SyntheticDeviceNodeMinted\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"addSyntheticDeviceAttribute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"syntheticDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"ownerSig\",\"type\":\"bytes\"}],\"name\":\"burnSyntheticDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getSyntheticDeviceIdByAddress\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"integrationNode\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"syntheticDeviceAddr\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairs\",\"type\":\"tuple[]\"}],\"internalType\":\"structMintSyntheticDeviceBatchInput[]\",\"name\":\"data\",\"type\":\"tuple[]\"}],\"name\":\"mintSyntheticDeviceBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"integrationNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"syntheticDeviceSig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"vehicleOwnerSig\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"syntheticDeviceAddr\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairs\",\"type\":\"tuple[]\"}],\"internalType\":\"structMintSyntheticDeviceInput\",\"name\":\"data\",\"type\":\"tuple\"}],\"name\":\"mintSyntheticDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setSyntheticDeviceIdProxyAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfo\",\"type\":\"tuple[]\"}],\"name\":\"setSyntheticDeviceInfo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"VehicleAttributeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"VehicleAttributeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"VehicleIdProxySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"VehicleNodeMinted\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"addVehicleAttribute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfo\",\"type\":\"tuple[]\"}],\"name\":\"mintVehicle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfo\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"mintVehicleSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setVehicleIdProxyAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfo\",\"type\":\"tuple[]\"}],\"name\":\"setVehicleInfo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"getInfo\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getParentNode\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"parentNode\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"name\":\"BeneficiarySet\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"name\":\"getBeneficiary\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"sourceNode\",\"type\":\"uint256\"}],\"name\":\"getLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"targetNode\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idProxyAddressSource\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"idProxyAddressTarget\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"sourceNode\",\"type\":\"uint256\"}],\"name\":\"getNodeLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"targetNode\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"name\":\"setAftermarketDeviceBeneficiary\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"UintUtils__InsufficientHexLength\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"moduleAddr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4[]\",\"name\":\"selectors\",\"type\":\"bytes4[]\"}],\"name\":\"ModuleAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"moduleAddr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4[]\",\"name\":\"selectors\",\"type\":\"bytes4[]\"}],\"name\":\"ModuleRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldImplementation\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4[]\",\"name\":\"oldSelectors\",\"type\":\"bytes4[]\"},{\"indexed\":false,\"internalType\":\"bytes4[]\",\"name\":\"newSelectors\",\"type\":\"bytes4[]\"}],\"name\":\"ModuleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"},{\"internalType\":\"bytes4[]\",\"name\":\"selectors\",\"type\":\"bytes4[]\"}],\"name\":\"addModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"},{\"internalType\":\"bytes4[]\",\"name\":\"selectors\",\"type\":\"bytes4[]\"}],\"name\":\"removeModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"oldImplementation\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes4[]\",\"name\":\"oldSelectors\",\"type\":\"bytes4[]\"},{\"internalType\":\"bytes4[]\",\"name\":\"newSelectors\",\"type\":\"bytes4[]\"}],\"name\":\"updateModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceTransferredDevAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"}],\"name\":\"AftermarketDeviceUnclaimedDevAdmin\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceUnpairedDevAdmin\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"internalType\":\"structDevAdmin.IdManufacturerName[]\",\"name\":\"idManufacturerNames\",\"type\":\"tuple[]\"}],\"name\":\"renameManufacturers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferAftermarketDeviceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"aftermarketDeviceNodes\",\"type\":\"uint256[]\"}],\"name\":\"unclaimAftermarketDeviceNode\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"aftermarketDeviceNodes\",\"type\":\"uint256[]\"}],\"name\":\"unpairAftermarketDeviceByDeviceNode\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"vehicleNodes\",\"type\":\"uint256[]\"}],\"name\":\"unpairAftermarketDeviceByVehicleNode\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"version\",\"type\":\"string\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multiDelegateCall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"}],\"name\":\"multiStaticCall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdMintCost\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"adMintCost\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_adMintCost\",\"type\":\"uint256\"}],\"name\":\"setAdMintCost\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_dimoToken\",\"type\":\"address\"}],\"name\":\"setDimoToken\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_foundation\",\"type\":\"address\"}],\"name\":\"setFoundationAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_license\",\"type\":\"address\"}],\"name\":\"setLicense\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"AdNotClaimed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"AdNotPaired\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"AdPaired\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attr\",\"type\":\"string\"}],\"name\":\"AttributeExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attr\",\"type\":\"string\"}],\"name\":\"AttributeNotWhitelisted\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"DeviceAlreadyClaimed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"DeviceAlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAdSignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidLicense\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"InvalidNode\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidOwnerSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"InvalidParentNode\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OwnersDoesNotMatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistryNotApproved\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"VehicleNotPaired\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"VehiclePaired\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"AftermarketDeviceAttributeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"AftermarketDeviceAttributeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceIdProxySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"manufacturerId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"aftermarketDeviceAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceNodeMinted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"AftermarketDevicePaired\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"AftermarketDeviceUnpaired\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"addAftermarketDeviceAttribute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerNode\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNodeId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"internalType\":\"structAftermarketDeviceOwnerPair[]\",\"name\":\"adOwnerPair\",\"type\":\"tuple[]\"}],\"name\":\"claimAftermarketDeviceBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"ownerSig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"aftermarketDeviceSig\",\"type\":\"bytes\"}],\"name\":\"claimAftermarketDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getAftermarketDeviceIdByAddress\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerNode\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairs\",\"type\":\"tuple[]\"}],\"internalType\":\"structAftermarketDeviceInfos[]\",\"name\":\"adInfos\",\"type\":\"tuple[]\"}],\"name\":\"mintAftermarketDeviceByManufacturerBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"aftermarketDeviceSig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"vehicleOwnerSig\",\"type\":\"bytes\"}],\"name\":\"pairAftermarketDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"pairAftermarketDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setAftermarketDeviceIdProxyAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfo\",\"type\":\"tuple[]\"}],\"name\":\"setAftermarketDeviceInfo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"}],\"name\":\"unpairAftermarketDevice\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"aftermarketDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"unpairAftermarketDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"controller\",\"type\":\"address\"}],\"name\":\"ControllerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"ManufacturerAttributeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"ManufacturerAttributeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"ManufacturerIdProxySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"ManufacturerNodeMinted\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"addManufacturerAttribute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"getManufacturerIdByName\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getManufacturerNameById\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isAllowedToOwnManufacturerNode\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isAllowed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isController\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isController\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isManufacturerMinted\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isManufacturerMinted\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairList\",\"type\":\"tuple[]\"}],\"name\":\"mintManufacturer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string[]\",\"name\":\"names\",\"type\":\"string[]\"}],\"name\":\"mintManufacturerBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_controller\",\"type\":\"address\"}],\"name\":\"setController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setManufacturerIdProxyAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoList\",\"type\":\"tuple[]\"}],\"name\":\"setManufacturerInfo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"updateManufacturerMinted\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"AlreadyController\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"IntegrationNameRegisterd\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"MustBeAdmin\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"NotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyNftProxy\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"IntegrationAttributeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"IntegrationAttributeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"IntegrationIdProxySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"IntegrationNodeMinted\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"addIntegrationAttribute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"getIntegrationIdByName\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getIntegrationNameById\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isAllowedToOwnIntegrationNode\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isAllowed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isIntegrationController\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isController\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isIntegrationMinted\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"_isIntegrationMinted\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairList\",\"type\":\"tuple[]\"}],\"name\":\"mintIntegration\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"string[]\",\"name\":\"names\",\"type\":\"string[]\"}],\"name\":\"mintIntegrationBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_controller\",\"type\":\"address\"}],\"name\":\"setIntegrationController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setIntegrationIdProxyAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoList\",\"type\":\"tuple[]\"}],\"name\":\"setIntegrationInfo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"updateIntegrationMinted\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"InvalidSdSignature\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"SyntheticDeviceAttributeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"SyntheticDeviceAttributeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"SyntheticDeviceIdProxySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"syntheticDeviceNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SyntheticDeviceNodeBurned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"integrationNode\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"syntheticDeviceNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"syntheticDeviceAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SyntheticDeviceNodeMinted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"name\":\"VehicleAttributeSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"VehicleNodeMinted\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"addSyntheticDeviceAttribute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"syntheticDeviceNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"ownerSig\",\"type\":\"bytes\"}],\"name\":\"burnSyntheticDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getSyntheticDeviceIdByAddress\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"integrationNode\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"syntheticDeviceAddr\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairs\",\"type\":\"tuple[]\"}],\"internalType\":\"structMintSyntheticDeviceBatchInput[]\",\"name\":\"data\",\"type\":\"tuple[]\"}],\"name\":\"mintSyntheticDeviceBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"integrationNode\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"vehicleNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"syntheticDeviceSig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"vehicleOwnerSig\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"syntheticDeviceAddr\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairs\",\"type\":\"tuple[]\"}],\"internalType\":\"structMintSyntheticDeviceInput\",\"name\":\"data\",\"type\":\"tuple\"}],\"name\":\"mintSyntheticDeviceSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setSyntheticDeviceIdProxyAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfo\",\"type\":\"tuple[]\"}],\"name\":\"setSyntheticDeviceInfo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"VehicleAttributeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"VehicleIdProxySet\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"addVehicleAttribute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfo\",\"type\":\"tuple[]\"}],\"name\":\"mintVehicle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfo\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"mintVehicleSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setVehicleIdProxyAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfo\",\"type\":\"tuple[]\"}],\"name\":\"setVehicleInfo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"}],\"name\":\"getInfo\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getParentNode\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"parentNode\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"name\":\"BeneficiarySet\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"}],\"name\":\"getBeneficiary\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idProxyAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"sourceNode\",\"type\":\"uint256\"}],\"name\":\"getLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"targetNode\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idProxyAddressSource\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"idProxyAddressTarget\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"sourceNode\",\"type\":\"uint256\"}],\"name\":\"getNodeLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"targetNode\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nodeId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"name\":\"setAftermarketDeviceBeneficiary\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"manufacturerNode\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairsVehicle\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256\",\"name\":\"integrationNode\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"vehicleOwnerSig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"syntheticDeviceSig\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"syntheticDeviceAddr\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"string\",\"name\":\"attribute\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"info\",\"type\":\"string\"}],\"internalType\":\"structAttributeInfoPair[]\",\"name\":\"attrInfoPairsDevice\",\"type\":\"tuple[]\"}],\"internalType\":\"structMintVehicleAndSdInput\",\"name\":\"data\",\"type\":\"tuple\"}],\"name\":\"mintVehicleAndSdSign\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", } // RegistryABI is the input ABI used to generate the binding from. @@ -1271,6 +1283,27 @@ func (_Registry *RegistryTransactorSession) MintVehicle(manufacturerNode *big.In return _Registry.Contract.MintVehicle(&_Registry.TransactOpts, manufacturerNode, owner, attrInfo) } +// MintVehicleAndSdSign is a paid mutator transaction binding the contract method 0xfb1a28e8. +// +// Solidity: function mintVehicleAndSdSign((uint256,address,(string,string)[],uint256,bytes,bytes,address,(string,string)[]) data) returns() +func (_Registry *RegistryTransactor) MintVehicleAndSdSign(opts *bind.TransactOpts, data MintVehicleAndSdInput) (*types.Transaction, error) { + return _Registry.contract.Transact(opts, "mintVehicleAndSdSign", data) +} + +// MintVehicleAndSdSign is a paid mutator transaction binding the contract method 0xfb1a28e8. +// +// Solidity: function mintVehicleAndSdSign((uint256,address,(string,string)[],uint256,bytes,bytes,address,(string,string)[]) data) returns() +func (_Registry *RegistrySession) MintVehicleAndSdSign(data MintVehicleAndSdInput) (*types.Transaction, error) { + return _Registry.Contract.MintVehicleAndSdSign(&_Registry.TransactOpts, data) +} + +// MintVehicleAndSdSign is a paid mutator transaction binding the contract method 0xfb1a28e8. +// +// Solidity: function mintVehicleAndSdSign((uint256,address,(string,string)[],uint256,bytes,bytes,address,(string,string)[]) data) returns() +func (_Registry *RegistryTransactorSession) MintVehicleAndSdSign(data MintVehicleAndSdInput) (*types.Transaction, error) { + return _Registry.Contract.MintVehicleAndSdSign(&_Registry.TransactOpts, data) +} + // MintVehicleSign is a paid mutator transaction binding the contract method 0x1b1a82c8. // // Solidity: function mintVehicleSign(uint256 manufacturerNode, address owner, (string,string)[] attrInfo, bytes signature) returns() @@ -1838,6 +1871,27 @@ func (_Registry *RegistryTransactorSession) UnclaimAftermarketDeviceNode(afterma return _Registry.Contract.UnclaimAftermarketDeviceNode(&_Registry.TransactOpts, aftermarketDeviceNodes) } +// UnpairAftermarketDevice is a paid mutator transaction binding the contract method 0xee4d9596. +// +// Solidity: function unpairAftermarketDevice(uint256 aftermarketDeviceNode, uint256 vehicleNode) returns() +func (_Registry *RegistryTransactor) UnpairAftermarketDevice(opts *bind.TransactOpts, aftermarketDeviceNode *big.Int, vehicleNode *big.Int) (*types.Transaction, error) { + return _Registry.contract.Transact(opts, "unpairAftermarketDevice", aftermarketDeviceNode, vehicleNode) +} + +// UnpairAftermarketDevice is a paid mutator transaction binding the contract method 0xee4d9596. +// +// Solidity: function unpairAftermarketDevice(uint256 aftermarketDeviceNode, uint256 vehicleNode) returns() +func (_Registry *RegistrySession) UnpairAftermarketDevice(aftermarketDeviceNode *big.Int, vehicleNode *big.Int) (*types.Transaction, error) { + return _Registry.Contract.UnpairAftermarketDevice(&_Registry.TransactOpts, aftermarketDeviceNode, vehicleNode) +} + +// UnpairAftermarketDevice is a paid mutator transaction binding the contract method 0xee4d9596. +// +// Solidity: function unpairAftermarketDevice(uint256 aftermarketDeviceNode, uint256 vehicleNode) returns() +func (_Registry *RegistryTransactorSession) UnpairAftermarketDevice(aftermarketDeviceNode *big.Int, vehicleNode *big.Int) (*types.Transaction, error) { + return _Registry.Contract.UnpairAftermarketDevice(&_Registry.TransactOpts, aftermarketDeviceNode, vehicleNode) +} + // UnpairAftermarketDeviceByDeviceNode is a paid mutator transaction binding the contract method 0x71193956. // // Solidity: function unpairAftermarketDeviceByDeviceNode(uint256[] aftermarketDeviceNodes) returns() diff --git a/internal/controllers/synthetic_devices_controller.go b/internal/controllers/synthetic_devices_controller.go index 8c556fe57..952a8d102 100644 --- a/internal/controllers/synthetic_devices_controller.go +++ b/internal/controllers/synthetic_devices_controller.go @@ -344,9 +344,8 @@ func (sdc *SyntheticDevicesController) MintSyntheticDevice(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusInternalServerError, "synthetic device minting request failed") } - vnID := types.NewDecimal(decimal.New(vid, 0)) syntheticDevice := &models.SyntheticDevice{ - VehicleTokenID: vnID, + VehicleTokenID: types.NewNullDecimal(decimal.New(vid, 0)), IntegrationTokenID: types.NewDecimal(decimal.New(int64(integrationNode), 0)), WalletChildNumber: childKeyNumber, WalletAddress: syntheticDeviceAddr, diff --git a/internal/controllers/synthetic_devices_controller_test.go b/internal/controllers/synthetic_devices_controller_test.go index 16b3a9530..46df6d073 100644 --- a/internal/controllers/synthetic_devices_controller_test.go +++ b/internal/controllers/synthetic_devices_controller_test.go @@ -337,7 +337,7 @@ func (s *SyntheticDevicesControllerTestSuite) Test_MintSyntheticDeviceSmartcar() SyntheticDeviceSig: vehicleSig, } - vnID := types.NewDecimal(decimal.New(57, 0)) + vnID := types.NewNullDecimal(decimal.New(57, 0)) syntDevice, err := models.SyntheticDevices( models.SyntheticDeviceWhere.VehicleTokenID.EQ(vnID), models.SyntheticDeviceWhere.IntegrationTokenID.EQ(types.NewDecimal(decimal.New(1, 0))), @@ -462,7 +462,7 @@ func (s *SyntheticDevicesControllerTestSuite) TestMintTesla() { SyntheticDeviceSig: vehicleSig, } - vnID := types.NewDecimal(decimal.New(int64(vehicleNode), 0)) + vnID := types.NewNullDecimal(decimal.New(int64(vehicleNode), 0)) syntDevice, err := models.SyntheticDevices( models.SyntheticDeviceWhere.VehicleTokenID.EQ(vnID), models.SyntheticDeviceWhere.IntegrationTokenID.EQ(types.NewDecimal(decimal.New(int64(integrationID), 0))), diff --git a/internal/services/registry/storage_test.go b/internal/services/registry/storage_test.go index 412a53399..725c12e37 100644 --- a/internal/services/registry/storage_test.go +++ b/internal/services/registry/storage_test.go @@ -124,7 +124,7 @@ func (s *StorageTestSuite) Test_SmartCar_StartPollOnMint() { } s.MustInsert(&syntMtr) - vnID := types.NewDecimal(decimal.New(vehicleID, 0)) + vnID := types.NewNullDecimal(decimal.New(vehicleID, 0)) syntheticDevice := models.SyntheticDevice{ VehicleTokenID: vnID, IntegrationTokenID: types.NewDecimal(decimal.New(integrationNode, 0)), @@ -229,7 +229,7 @@ func (s *StorageTestSuite) Test_Tesla_StartPollOnMint() { } s.MustInsert(&syntMtx) - vnID := types.NewDecimal(decimal.New(vehicleID, 0)) + vnID := types.NewNullDecimal(decimal.New(vehicleID, 0)) syntheticDevice := models.SyntheticDevice{ VehicleTokenID: vnID, IntegrationTokenID: types.NewDecimal(decimal.New(integrationNode, 0)), @@ -348,7 +348,7 @@ func (s *StorageTestSuite) Test_InvalidOEMInMetaTx() { } s.MustInsert(&syntMtr) - vnID := types.NewDecimal(decimal.New(vehicleID, 0)) + vnID := types.NewNullDecimal(decimal.New(vehicleID, 0)) syntheticDevice := models.SyntheticDevice{ VehicleTokenID: vnID, IntegrationTokenID: types.NewDecimal(decimal.New(integrationNode, 0)), diff --git a/migrations/20230720215147_synthetic_multi_mint.sql b/migrations/20230720215147_synthetic_multi_mint.sql new file mode 100644 index 000000000..6a6f9bca4 --- /dev/null +++ b/migrations/20230720215147_synthetic_multi_mint.sql @@ -0,0 +1,14 @@ +-- +goose Up +-- +goose StatementBegin +SET search_path = devices_api, public; + +ALTER TABLE synthetic_devices ADD CONSTRAINT synthetic_devices_vehicle_token_id_integration_token_id_key UNIQUE (vehicle_token_id, integration_token_id); +ALTER TABLE synthetic_devices DROP CONSTRAINT synthetic_devices_pkey; +ALTER TABLE synthetic_devices ALTER COLUMN vehicle_token_id DROP NOT NULL; +ALTER TABLE synthetic_devices ADD CONSTRAINT synthetic_devices_pkey PRIMARY KEY (mint_request_id); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +SET search_path = devices_api, public; +-- +goose StatementEnd diff --git a/models/external_vin_data.go b/models/external_vin_data.go index 396edafb1..10354e305 100644 --- a/models/external_vin_data.go +++ b/models/external_vin_data.go @@ -199,10 +199,14 @@ var ExternalVinDatumWhere = struct { // ExternalVinDatumRels is where relationship names are stored. var ExternalVinDatumRels = struct { -}{} + UserDevice string +}{ + UserDevice: "UserDevice", +} // externalVinDatumR is where relationships are stored. type externalVinDatumR struct { + UserDevice *UserDevice `boil:"UserDevice" json:"UserDevice" toml:"UserDevice" yaml:"UserDevice"` } // NewStruct creates a new relationship struct @@ -210,6 +214,13 @@ func (*externalVinDatumR) NewStruct() *externalVinDatumR { return &externalVinDatumR{} } +func (r *externalVinDatumR) GetUserDevice() *UserDevice { + if r == nil { + return nil + } + return r.UserDevice +} + // externalVinDatumL is where Load methods for each relationship are stored. type externalVinDatumL struct{} @@ -499,6 +510,221 @@ func (q externalVinDatumQuery) Exists(ctx context.Context, exec boil.ContextExec return count > 0, nil } +// UserDevice pointed to by the foreign key. +func (o *ExternalVinDatum) UserDevice(mods ...qm.QueryMod) userDeviceQuery { + queryMods := []qm.QueryMod{ + qm.Where("\"id\" = ?", o.UserDeviceID), + } + + queryMods = append(queryMods, mods...) + + return UserDevices(queryMods...) +} + +// LoadUserDevice allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for an N-1 relationship. +func (externalVinDatumL) LoadUserDevice(ctx context.Context, e boil.ContextExecutor, singular bool, maybeExternalVinDatum interface{}, mods queries.Applicator) error { + var slice []*ExternalVinDatum + var object *ExternalVinDatum + + if singular { + var ok bool + object, ok = maybeExternalVinDatum.(*ExternalVinDatum) + if !ok { + object = new(ExternalVinDatum) + ok = queries.SetFromEmbeddedStruct(&object, &maybeExternalVinDatum) + if !ok { + return errors.New(fmt.Sprintf("failed to set %T from embedded struct %T", object, maybeExternalVinDatum)) + } + } + } else { + s, ok := maybeExternalVinDatum.(*[]*ExternalVinDatum) + if ok { + slice = *s + } else { + ok = queries.SetFromEmbeddedStruct(&slice, maybeExternalVinDatum) + if !ok { + return errors.New(fmt.Sprintf("failed to set %T from embedded struct %T", slice, maybeExternalVinDatum)) + } + } + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &externalVinDatumR{} + } + if !queries.IsNil(object.UserDeviceID) { + args = append(args, object.UserDeviceID) + } + + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &externalVinDatumR{} + } + + for _, a := range args { + if queries.Equal(a, obj.UserDeviceID) { + continue Outer + } + } + + if !queries.IsNil(obj.UserDeviceID) { + args = append(args, obj.UserDeviceID) + } + + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery( + qm.From(`devices_api.user_devices`), + qm.WhereIn(`devices_api.user_devices.id in ?`, args...), + ) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load UserDevice") + } + + var resultSlice []*UserDevice + if err = queries.Bind(results, &resultSlice); err != nil { + return errors.Wrap(err, "failed to bind eager loaded slice UserDevice") + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results of eager load for user_devices") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for user_devices") + } + + if len(userDeviceAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + + if len(resultSlice) == 0 { + return nil + } + + if singular { + foreign := resultSlice[0] + object.R.UserDevice = foreign + if foreign.R == nil { + foreign.R = &userDeviceR{} + } + foreign.R.ExternalVinData = append(foreign.R.ExternalVinData, object) + return nil + } + + for _, local := range slice { + for _, foreign := range resultSlice { + if queries.Equal(local.UserDeviceID, foreign.ID) { + local.R.UserDevice = foreign + if foreign.R == nil { + foreign.R = &userDeviceR{} + } + foreign.R.ExternalVinData = append(foreign.R.ExternalVinData, local) + break + } + } + } + + return nil +} + +// SetUserDevice of the externalVinDatum to the related item. +// Sets o.R.UserDevice to related. +// Adds o to related.R.ExternalVinData. +func (o *ExternalVinDatum) SetUserDevice(ctx context.Context, exec boil.ContextExecutor, insert bool, related *UserDevice) error { + var err error + if insert { + if err = related.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } + + updateQuery := fmt.Sprintf( + "UPDATE \"devices_api\".\"external_vin_data\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 1, []string{"user_device_id"}), + strmangle.WhereClause("\"", "\"", 2, externalVinDatumPrimaryKeyColumns), + ) + values := []interface{}{related.ID, o.ID} + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, updateQuery) + fmt.Fprintln(writer, values) + } + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + queries.Assign(&o.UserDeviceID, related.ID) + if o.R == nil { + o.R = &externalVinDatumR{ + UserDevice: related, + } + } else { + o.R.UserDevice = related + } + + if related.R == nil { + related.R = &userDeviceR{ + ExternalVinData: ExternalVinDatumSlice{o}, + } + } else { + related.R.ExternalVinData = append(related.R.ExternalVinData, o) + } + + return nil +} + +// RemoveUserDevice relationship. +// Sets o.R.UserDevice to nil. +// Removes o from all passed in related items' relationships struct. +func (o *ExternalVinDatum) RemoveUserDevice(ctx context.Context, exec boil.ContextExecutor, related *UserDevice) error { + var err error + + queries.SetScanner(&o.UserDeviceID, nil) + if _, err = o.Update(ctx, exec, boil.Whitelist("user_device_id")); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + if o.R != nil { + o.R.UserDevice = nil + } + if related == nil || related.R == nil { + return nil + } + + for i, ri := range related.R.ExternalVinData { + if queries.Equal(o.UserDeviceID, ri.UserDeviceID) { + continue + } + + ln := len(related.R.ExternalVinData) + if ln > 1 && i < ln-1 { + related.R.ExternalVinData[i] = related.R.ExternalVinData[ln-1] + } + related.R.ExternalVinData = related.R.ExternalVinData[:ln-1] + break + } + return nil +} + // ExternalVinData retrieves all the records using an executor. func ExternalVinData(mods ...qm.QueryMod) externalVinDatumQuery { mods = append(mods, qm.From("\"devices_api\".\"external_vin_data\"")) diff --git a/models/meta_transaction_requests.go b/models/meta_transaction_requests.go index 2daaa110f..a6b4a18f8 100644 --- a/models/meta_transaction_requests.go +++ b/models/meta_transaction_requests.go @@ -1449,7 +1449,7 @@ func (o *MetaTransactionRequest) SetMintRequestSyntheticDevice(ctx context.Conte strmangle.SetParamNames("\"", "\"", 1, []string{"mint_request_id"}), strmangle.WhereClause("\"", "\"", 2, syntheticDevicePrimaryKeyColumns), ) - values := []interface{}{o.ID, related.VehicleTokenID, related.IntegrationTokenID} + values := []interface{}{o.ID, related.MintRequestID} if boil.IsDebug(ctx) { writer := boil.DebugWriterFrom(ctx) @@ -1499,7 +1499,7 @@ func (o *MetaTransactionRequest) SetBurnRequestSyntheticDevice(ctx context.Conte strmangle.SetParamNames("\"", "\"", 1, []string{"burn_request_id"}), strmangle.WhereClause("\"", "\"", 2, syntheticDevicePrimaryKeyColumns), ) - values := []interface{}{o.ID, related.VehicleTokenID, related.IntegrationTokenID} + values := []interface{}{o.ID, related.MintRequestID} if boil.IsDebug(ctx) { writer := boil.DebugWriterFrom(ctx) diff --git a/models/synthetic_devices.go b/models/synthetic_devices.go index 810b1b879..49253e1dd 100644 --- a/models/synthetic_devices.go +++ b/models/synthetic_devices.go @@ -25,7 +25,7 @@ import ( // SyntheticDevice is an object representing the database table. type SyntheticDevice struct { - VehicleTokenID types.Decimal `boil:"vehicle_token_id" json:"vehicle_token_id" toml:"vehicle_token_id" yaml:"vehicle_token_id"` + VehicleTokenID types.NullDecimal `boil:"vehicle_token_id" json:"vehicle_token_id,omitempty" toml:"vehicle_token_id" yaml:"vehicle_token_id,omitempty"` IntegrationTokenID types.Decimal `boil:"integration_token_id" json:"integration_token_id" toml:"integration_token_id" yaml:"integration_token_id"` MintRequestID string `boil:"mint_request_id" json:"mint_request_id" toml:"mint_request_id" yaml:"mint_request_id"` WalletChildNumber int `boil:"wallet_child_number" json:"wallet_child_number" toml:"wallet_child_number" yaml:"wallet_child_number"` @@ -99,7 +99,7 @@ func (w whereHelperint) NIN(slice []int) qm.QueryMod { } var SyntheticDeviceWhere = struct { - VehicleTokenID whereHelpertypes_Decimal + VehicleTokenID whereHelpertypes_NullDecimal IntegrationTokenID whereHelpertypes_Decimal MintRequestID whereHelperstring WalletChildNumber whereHelperint @@ -107,7 +107,7 @@ var SyntheticDeviceWhere = struct { TokenID whereHelpertypes_NullDecimal BurnRequestID whereHelpernull_String }{ - VehicleTokenID: whereHelpertypes_Decimal{field: "\"devices_api\".\"synthetic_devices\".\"vehicle_token_id\""}, + VehicleTokenID: whereHelpertypes_NullDecimal{field: "\"devices_api\".\"synthetic_devices\".\"vehicle_token_id\""}, IntegrationTokenID: whereHelpertypes_Decimal{field: "\"devices_api\".\"synthetic_devices\".\"integration_token_id\""}, MintRequestID: whereHelperstring{field: "\"devices_api\".\"synthetic_devices\".\"mint_request_id\""}, WalletChildNumber: whereHelperint{field: "\"devices_api\".\"synthetic_devices\".\"wallet_child_number\""}, @@ -165,9 +165,9 @@ type syntheticDeviceL struct{} var ( syntheticDeviceAllColumns = []string{"vehicle_token_id", "integration_token_id", "mint_request_id", "wallet_child_number", "wallet_address", "token_id", "burn_request_id"} - syntheticDeviceColumnsWithoutDefault = []string{"vehicle_token_id", "integration_token_id", "mint_request_id", "wallet_child_number", "wallet_address"} - syntheticDeviceColumnsWithDefault = []string{"token_id", "burn_request_id"} - syntheticDevicePrimaryKeyColumns = []string{"vehicle_token_id", "integration_token_id"} + syntheticDeviceColumnsWithoutDefault = []string{"integration_token_id", "mint_request_id", "wallet_child_number", "wallet_address"} + syntheticDeviceColumnsWithDefault = []string{"vehicle_token_id", "token_id", "burn_request_id"} + syntheticDevicePrimaryKeyColumns = []string{"mint_request_id"} syntheticDeviceGeneratedColumns = []string{} ) @@ -866,7 +866,7 @@ func (o *SyntheticDevice) SetMintRequest(ctx context.Context, exec boil.ContextE strmangle.SetParamNames("\"", "\"", 1, []string{"mint_request_id"}), strmangle.WhereClause("\"", "\"", 2, syntheticDevicePrimaryKeyColumns), ) - values := []interface{}{related.ID, o.VehicleTokenID, o.IntegrationTokenID} + values := []interface{}{related.ID, o.MintRequestID} if boil.IsDebug(ctx) { writer := boil.DebugWriterFrom(ctx) @@ -913,7 +913,7 @@ func (o *SyntheticDevice) SetVehicleToken(ctx context.Context, exec boil.Context strmangle.SetParamNames("\"", "\"", 1, []string{"vehicle_token_id"}), strmangle.WhereClause("\"", "\"", 2, syntheticDevicePrimaryKeyColumns), ) - values := []interface{}{related.TokenID, o.VehicleTokenID, o.IntegrationTokenID} + values := []interface{}{related.TokenID, o.MintRequestID} if boil.IsDebug(ctx) { writer := boil.DebugWriterFrom(ctx) @@ -944,6 +944,39 @@ func (o *SyntheticDevice) SetVehicleToken(ctx context.Context, exec boil.Context return nil } +// RemoveVehicleToken relationship. +// Sets o.R.VehicleToken to nil. +// Removes o from all passed in related items' relationships struct. +func (o *SyntheticDevice) RemoveVehicleToken(ctx context.Context, exec boil.ContextExecutor, related *VehicleNFT) error { + var err error + + queries.SetScanner(&o.VehicleTokenID, nil) + if _, err = o.Update(ctx, exec, boil.Whitelist("vehicle_token_id")); err != nil { + return errors.Wrap(err, "failed to update local table") + } + + if o.R != nil { + o.R.VehicleToken = nil + } + if related == nil || related.R == nil { + return nil + } + + for i, ri := range related.R.VehicleTokenSyntheticDevices { + if queries.Equal(o.VehicleTokenID, ri.VehicleTokenID) { + continue + } + + ln := len(related.R.VehicleTokenSyntheticDevices) + if ln > 1 && i < ln-1 { + related.R.VehicleTokenSyntheticDevices[i] = related.R.VehicleTokenSyntheticDevices[ln-1] + } + related.R.VehicleTokenSyntheticDevices = related.R.VehicleTokenSyntheticDevices[:ln-1] + break + } + return nil +} + // SetBurnRequest of the syntheticDevice to the related item. // Sets o.R.BurnRequest to related. // Adds o to related.R.BurnRequestSyntheticDevice. @@ -960,7 +993,7 @@ func (o *SyntheticDevice) SetBurnRequest(ctx context.Context, exec boil.ContextE strmangle.SetParamNames("\"", "\"", 1, []string{"burn_request_id"}), strmangle.WhereClause("\"", "\"", 2, syntheticDevicePrimaryKeyColumns), ) - values := []interface{}{related.ID, o.VehicleTokenID, o.IntegrationTokenID} + values := []interface{}{related.ID, o.MintRequestID} if boil.IsDebug(ctx) { writer := boil.DebugWriterFrom(ctx) @@ -1026,7 +1059,7 @@ func SyntheticDevices(mods ...qm.QueryMod) syntheticDeviceQuery { // FindSyntheticDevice retrieves a single record by ID with an executor. // If selectCols is empty Find will return all columns. -func FindSyntheticDevice(ctx context.Context, exec boil.ContextExecutor, vehicleTokenID types.Decimal, integrationTokenID types.Decimal, selectCols ...string) (*SyntheticDevice, error) { +func FindSyntheticDevice(ctx context.Context, exec boil.ContextExecutor, mintRequestID string, selectCols ...string) (*SyntheticDevice, error) { syntheticDeviceObj := &SyntheticDevice{} sel := "*" @@ -1034,10 +1067,10 @@ func FindSyntheticDevice(ctx context.Context, exec boil.ContextExecutor, vehicle sel = strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, selectCols), ",") } query := fmt.Sprintf( - "select %s from \"devices_api\".\"synthetic_devices\" where \"vehicle_token_id\"=$1 AND \"integration_token_id\"=$2", sel, + "select %s from \"devices_api\".\"synthetic_devices\" where \"mint_request_id\"=$1", sel, ) - q := queries.Raw(query, vehicleTokenID, integrationTokenID) + q := queries.Raw(query, mintRequestID) err := q.Bind(ctx, exec, syntheticDeviceObj) if err != nil { @@ -1389,7 +1422,7 @@ func (o *SyntheticDevice) Delete(ctx context.Context, exec boil.ContextExecutor) } args := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), syntheticDevicePrimaryKeyMapping) - sql := "DELETE FROM \"devices_api\".\"synthetic_devices\" WHERE \"vehicle_token_id\"=$1 AND \"integration_token_id\"=$2" + sql := "DELETE FROM \"devices_api\".\"synthetic_devices\" WHERE \"mint_request_id\"=$1" if boil.IsDebug(ctx) { writer := boil.DebugWriterFrom(ctx) @@ -1486,7 +1519,7 @@ func (o SyntheticDeviceSlice) DeleteAll(ctx context.Context, exec boil.ContextEx // Reload refetches the object from the database // using the primary keys with an executor. func (o *SyntheticDevice) Reload(ctx context.Context, exec boil.ContextExecutor) error { - ret, err := FindSyntheticDevice(ctx, exec, o.VehicleTokenID, o.IntegrationTokenID) + ret, err := FindSyntheticDevice(ctx, exec, o.MintRequestID) if err != nil { return err } @@ -1525,16 +1558,16 @@ func (o *SyntheticDeviceSlice) ReloadAll(ctx context.Context, exec boil.ContextE } // SyntheticDeviceExists checks if the SyntheticDevice row exists. -func SyntheticDeviceExists(ctx context.Context, exec boil.ContextExecutor, vehicleTokenID types.Decimal, integrationTokenID types.Decimal) (bool, error) { +func SyntheticDeviceExists(ctx context.Context, exec boil.ContextExecutor, mintRequestID string) (bool, error) { var exists bool - sql := "select exists(select 1 from \"devices_api\".\"synthetic_devices\" where \"vehicle_token_id\"=$1 AND \"integration_token_id\"=$2 limit 1)" + sql := "select exists(select 1 from \"devices_api\".\"synthetic_devices\" where \"mint_request_id\"=$1 limit 1)" if boil.IsDebug(ctx) { writer := boil.DebugWriterFrom(ctx) fmt.Fprintln(writer, sql) - fmt.Fprintln(writer, vehicleTokenID, integrationTokenID) + fmt.Fprintln(writer, mintRequestID) } - row := exec.QueryRowContext(ctx, sql, vehicleTokenID, integrationTokenID) + row := exec.QueryRowContext(ctx, sql, mintRequestID) err := row.Scan(&exists) if err != nil { @@ -1546,5 +1579,5 @@ func SyntheticDeviceExists(ctx context.Context, exec boil.ContextExecutor, vehic // Exists checks if the SyntheticDevice row exists. func (o *SyntheticDevice) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) { - return SyntheticDeviceExists(ctx, exec, o.VehicleTokenID, o.IntegrationTokenID) + return SyntheticDeviceExists(ctx, exec, o.MintRequestID) } diff --git a/models/user_devices.go b/models/user_devices.go index db2269d01..e10d5c184 100644 --- a/models/user_devices.go +++ b/models/user_devices.go @@ -149,6 +149,7 @@ var UserDeviceRels = struct { AutopiJobs string DeviceCommandRequests string ErrorCodeQueries string + ExternalVinData string UserDeviceAPIIntegrations string UserDeviceData string UserDeviceToGeofences string @@ -157,6 +158,7 @@ var UserDeviceRels = struct { AutopiJobs: "AutopiJobs", DeviceCommandRequests: "DeviceCommandRequests", ErrorCodeQueries: "ErrorCodeQueries", + ExternalVinData: "ExternalVinData", UserDeviceAPIIntegrations: "UserDeviceAPIIntegrations", UserDeviceData: "UserDeviceData", UserDeviceToGeofences: "UserDeviceToGeofences", @@ -168,6 +170,7 @@ type userDeviceR struct { AutopiJobs AutopiJobSlice `boil:"AutopiJobs" json:"AutopiJobs" toml:"AutopiJobs" yaml:"AutopiJobs"` DeviceCommandRequests DeviceCommandRequestSlice `boil:"DeviceCommandRequests" json:"DeviceCommandRequests" toml:"DeviceCommandRequests" yaml:"DeviceCommandRequests"` ErrorCodeQueries ErrorCodeQuerySlice `boil:"ErrorCodeQueries" json:"ErrorCodeQueries" toml:"ErrorCodeQueries" yaml:"ErrorCodeQueries"` + ExternalVinData ExternalVinDatumSlice `boil:"ExternalVinData" json:"ExternalVinData" toml:"ExternalVinData" yaml:"ExternalVinData"` UserDeviceAPIIntegrations UserDeviceAPIIntegrationSlice `boil:"UserDeviceAPIIntegrations" json:"UserDeviceAPIIntegrations" toml:"UserDeviceAPIIntegrations" yaml:"UserDeviceAPIIntegrations"` UserDeviceData UserDeviceDatumSlice `boil:"UserDeviceData" json:"UserDeviceData" toml:"UserDeviceData" yaml:"UserDeviceData"` UserDeviceToGeofences UserDeviceToGeofenceSlice `boil:"UserDeviceToGeofences" json:"UserDeviceToGeofences" toml:"UserDeviceToGeofences" yaml:"UserDeviceToGeofences"` @@ -206,6 +209,13 @@ func (r *userDeviceR) GetErrorCodeQueries() ErrorCodeQuerySlice { return r.ErrorCodeQueries } +func (r *userDeviceR) GetExternalVinData() ExternalVinDatumSlice { + if r == nil { + return nil + } + return r.ExternalVinData +} + func (r *userDeviceR) GetUserDeviceAPIIntegrations() UserDeviceAPIIntegrationSlice { if r == nil { return nil @@ -569,6 +579,20 @@ func (o *UserDevice) ErrorCodeQueries(mods ...qm.QueryMod) errorCodeQueryQuery { return ErrorCodeQueries(queryMods...) } +// ExternalVinData retrieves all the external_vin_datum's ExternalVinData with an executor. +func (o *UserDevice) ExternalVinData(mods ...qm.QueryMod) externalVinDatumQuery { + var queryMods []qm.QueryMod + if len(mods) != 0 { + queryMods = append(queryMods, mods...) + } + + queryMods = append(queryMods, + qm.Where("\"devices_api\".\"external_vin_data\".\"user_device_id\"=?", o.ID), + ) + + return ExternalVinData(queryMods...) +} + // UserDeviceAPIIntegrations retrieves all the user_device_api_integration's UserDeviceAPIIntegrations with an executor. func (o *UserDevice) UserDeviceAPIIntegrations(mods ...qm.QueryMod) userDeviceAPIIntegrationQuery { var queryMods []qm.QueryMod @@ -1070,6 +1094,120 @@ func (userDeviceL) LoadErrorCodeQueries(ctx context.Context, e boil.ContextExecu return nil } +// LoadExternalVinData allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for a 1-M or N-M relationship. +func (userDeviceL) LoadExternalVinData(ctx context.Context, e boil.ContextExecutor, singular bool, maybeUserDevice interface{}, mods queries.Applicator) error { + var slice []*UserDevice + var object *UserDevice + + if singular { + var ok bool + object, ok = maybeUserDevice.(*UserDevice) + if !ok { + object = new(UserDevice) + ok = queries.SetFromEmbeddedStruct(&object, &maybeUserDevice) + if !ok { + return errors.New(fmt.Sprintf("failed to set %T from embedded struct %T", object, maybeUserDevice)) + } + } + } else { + s, ok := maybeUserDevice.(*[]*UserDevice) + if ok { + slice = *s + } else { + ok = queries.SetFromEmbeddedStruct(&slice, maybeUserDevice) + if !ok { + return errors.New(fmt.Sprintf("failed to set %T from embedded struct %T", slice, maybeUserDevice)) + } + } + } + + args := make([]interface{}, 0, 1) + if singular { + if object.R == nil { + object.R = &userDeviceR{} + } + args = append(args, object.ID) + } else { + Outer: + for _, obj := range slice { + if obj.R == nil { + obj.R = &userDeviceR{} + } + + for _, a := range args { + if queries.Equal(a, obj.ID) { + continue Outer + } + } + + args = append(args, obj.ID) + } + } + + if len(args) == 0 { + return nil + } + + query := NewQuery( + qm.From(`devices_api.external_vin_data`), + qm.WhereIn(`devices_api.external_vin_data.user_device_id in ?`, args...), + ) + if mods != nil { + mods.Apply(query) + } + + results, err := query.QueryContext(ctx, e) + if err != nil { + return errors.Wrap(err, "failed to eager load external_vin_data") + } + + var resultSlice []*ExternalVinDatum + if err = queries.Bind(results, &resultSlice); err != nil { + return errors.Wrap(err, "failed to bind eager loaded slice external_vin_data") + } + + if err = results.Close(); err != nil { + return errors.Wrap(err, "failed to close results in eager load on external_vin_data") + } + if err = results.Err(); err != nil { + return errors.Wrap(err, "error occurred during iteration of eager loaded relations for external_vin_data") + } + + if len(externalVinDatumAfterSelectHooks) != 0 { + for _, obj := range resultSlice { + if err := obj.doAfterSelectHooks(ctx, e); err != nil { + return err + } + } + } + if singular { + object.R.ExternalVinData = resultSlice + for _, foreign := range resultSlice { + if foreign.R == nil { + foreign.R = &externalVinDatumR{} + } + foreign.R.UserDevice = object + } + return nil + } + + for _, foreign := range resultSlice { + for _, local := range slice { + if queries.Equal(local.ID, foreign.UserDeviceID) { + local.R.ExternalVinData = append(local.R.ExternalVinData, foreign) + if foreign.R == nil { + foreign.R = &externalVinDatumR{} + } + foreign.R.UserDevice = local + break + } + } + } + + return nil +} + // LoadUserDeviceAPIIntegrations allows an eager lookup of values, cached into the // loaded structs of the objects. This is for a 1-M or N-M relationship. func (userDeviceL) LoadUserDeviceAPIIntegrations(ctx context.Context, e boil.ContextExecutor, singular bool, maybeUserDevice interface{}, mods queries.Applicator) error { @@ -1719,6 +1857,133 @@ func (o *UserDevice) AddErrorCodeQueries(ctx context.Context, exec boil.ContextE return nil } +// AddExternalVinData adds the given related objects to the existing relationships +// of the user_device, optionally inserting them as new records. +// Appends related to o.R.ExternalVinData. +// Sets related.R.UserDevice appropriately. +func (o *UserDevice) AddExternalVinData(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*ExternalVinDatum) error { + var err error + for _, rel := range related { + if insert { + queries.Assign(&rel.UserDeviceID, o.ID) + if err = rel.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } else { + updateQuery := fmt.Sprintf( + "UPDATE \"devices_api\".\"external_vin_data\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 1, []string{"user_device_id"}), + strmangle.WhereClause("\"", "\"", 2, externalVinDatumPrimaryKeyColumns), + ) + values := []interface{}{o.ID, rel.ID} + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, updateQuery) + fmt.Fprintln(writer, values) + } + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update foreign table") + } + + queries.Assign(&rel.UserDeviceID, o.ID) + } + } + + if o.R == nil { + o.R = &userDeviceR{ + ExternalVinData: related, + } + } else { + o.R.ExternalVinData = append(o.R.ExternalVinData, related...) + } + + for _, rel := range related { + if rel.R == nil { + rel.R = &externalVinDatumR{ + UserDevice: o, + } + } else { + rel.R.UserDevice = o + } + } + return nil +} + +// SetExternalVinData removes all previously related items of the +// user_device replacing them completely with the passed +// in related items, optionally inserting them as new records. +// Sets o.R.UserDevice's ExternalVinData accordingly. +// Replaces o.R.ExternalVinData with related. +// Sets related.R.UserDevice's ExternalVinData accordingly. +func (o *UserDevice) SetExternalVinData(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*ExternalVinDatum) error { + query := "update \"devices_api\".\"external_vin_data\" set \"user_device_id\" = null where \"user_device_id\" = $1" + values := []interface{}{o.ID} + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, query) + fmt.Fprintln(writer, values) + } + _, err := exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to remove relationships before set") + } + + if o.R != nil { + for _, rel := range o.R.ExternalVinData { + queries.SetScanner(&rel.UserDeviceID, nil) + if rel.R == nil { + continue + } + + rel.R.UserDevice = nil + } + o.R.ExternalVinData = nil + } + + return o.AddExternalVinData(ctx, exec, insert, related...) +} + +// RemoveExternalVinData relationships from objects passed in. +// Removes related items from R.ExternalVinData (uses pointer comparison, removal does not keep order) +// Sets related.R.UserDevice. +func (o *UserDevice) RemoveExternalVinData(ctx context.Context, exec boil.ContextExecutor, related ...*ExternalVinDatum) error { + if len(related) == 0 { + return nil + } + + var err error + for _, rel := range related { + queries.SetScanner(&rel.UserDeviceID, nil) + if rel.R != nil { + rel.R.UserDevice = nil + } + if _, err = rel.Update(ctx, exec, boil.Whitelist("user_device_id")); err != nil { + return err + } + } + if o.R == nil { + return nil + } + + for _, rel := range related { + for i, ri := range o.R.ExternalVinData { + if rel != ri { + continue + } + + ln := len(o.R.ExternalVinData) + if ln > 1 && i < ln-1 { + o.R.ExternalVinData[i] = o.R.ExternalVinData[ln-1] + } + o.R.ExternalVinData = o.R.ExternalVinData[:ln-1] + break + } + } + + return nil +} + // AddUserDeviceAPIIntegrations adds the given related objects to the existing relationships // of the user_device, optionally inserting them as new records. // Appends related to o.R.UserDeviceAPIIntegrations. diff --git a/models/vehicle_nfts.go b/models/vehicle_nfts.go index a1ade1c1d..a2d5d350a 100644 --- a/models/vehicle_nfts.go +++ b/models/vehicle_nfts.go @@ -1373,7 +1373,7 @@ func (o *VehicleNFT) AddVehicleTokenSyntheticDevices(ctx context.Context, exec b strmangle.SetParamNames("\"", "\"", 1, []string{"vehicle_token_id"}), strmangle.WhereClause("\"", "\"", 2, syntheticDevicePrimaryKeyColumns), ) - values := []interface{}{o.TokenID, rel.VehicleTokenID, rel.IntegrationTokenID} + values := []interface{}{o.TokenID, rel.MintRequestID} if boil.IsDebug(ctx) { writer := boil.DebugWriterFrom(ctx) @@ -1408,6 +1408,80 @@ func (o *VehicleNFT) AddVehicleTokenSyntheticDevices(ctx context.Context, exec b return nil } +// SetVehicleTokenSyntheticDevices removes all previously related items of the +// vehicle_nft replacing them completely with the passed +// in related items, optionally inserting them as new records. +// Sets o.R.VehicleToken's VehicleTokenSyntheticDevices accordingly. +// Replaces o.R.VehicleTokenSyntheticDevices with related. +// Sets related.R.VehicleToken's VehicleTokenSyntheticDevices accordingly. +func (o *VehicleNFT) SetVehicleTokenSyntheticDevices(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*SyntheticDevice) error { + query := "update \"devices_api\".\"synthetic_devices\" set \"vehicle_token_id\" = null where \"vehicle_token_id\" = $1" + values := []interface{}{o.TokenID} + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, query) + fmt.Fprintln(writer, values) + } + _, err := exec.ExecContext(ctx, query, values...) + if err != nil { + return errors.Wrap(err, "failed to remove relationships before set") + } + + if o.R != nil { + for _, rel := range o.R.VehicleTokenSyntheticDevices { + queries.SetScanner(&rel.VehicleTokenID, nil) + if rel.R == nil { + continue + } + + rel.R.VehicleToken = nil + } + o.R.VehicleTokenSyntheticDevices = nil + } + + return o.AddVehicleTokenSyntheticDevices(ctx, exec, insert, related...) +} + +// RemoveVehicleTokenSyntheticDevices relationships from objects passed in. +// Removes related items from R.VehicleTokenSyntheticDevices (uses pointer comparison, removal does not keep order) +// Sets related.R.VehicleToken. +func (o *VehicleNFT) RemoveVehicleTokenSyntheticDevices(ctx context.Context, exec boil.ContextExecutor, related ...*SyntheticDevice) error { + if len(related) == 0 { + return nil + } + + var err error + for _, rel := range related { + queries.SetScanner(&rel.VehicleTokenID, nil) + if rel.R != nil { + rel.R.VehicleToken = nil + } + if _, err = rel.Update(ctx, exec, boil.Whitelist("vehicle_token_id")); err != nil { + return err + } + } + if o.R == nil { + return nil + } + + for _, rel := range related { + for i, ri := range o.R.VehicleTokenSyntheticDevices { + if rel != ri { + continue + } + + ln := len(o.R.VehicleTokenSyntheticDevices) + if ln > 1 && i < ln-1 { + o.R.VehicleTokenSyntheticDevices[i] = o.R.VehicleTokenSyntheticDevices[ln-1] + } + o.R.VehicleTokenSyntheticDevices = o.R.VehicleTokenSyntheticDevices[:ln-1] + break + } + } + + return nil +} + // VehicleNFTS retrieves all the records using an executor. func VehicleNFTS(mods ...qm.QueryMod) vehicleNFTQuery { mods = append(mods, qm.From("\"devices_api\".\"vehicle_nfts\"")) From d409c90154257033674a58e446331a9ef8221d6c Mon Sep 17 00:00:00 2001 From: Dylan Moreland Date: Mon, 24 Jul 2023 16:16:57 -0400 Subject: [PATCH 02/11] Remove some dependencies the SD doesn't need --- cmd/devices-api/api.go | 2 +- internal/services/registry/client.go | 15 +++++++++++ .../synthetic_device_instance_service.go | 27 +++---------------- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/cmd/devices-api/api.go b/cmd/devices-api/api.go index 7cd2a6885..bbed2b8c9 100644 --- a/cmd/devices-api/api.go +++ b/cmd/devices-api/api.go @@ -239,7 +239,7 @@ func startWebAPI(logger zerolog.Logger, settings *config.Settings, pdb db.Store, v1Auth.Get("/documents/:id/download", documentsController.DownloadDocument) if settings.SyntheticDevicesEnabled { - syntheticDeviceSvc, err := services.NewSyntheticWalletInstanceService(pdb.DBS, settings) + syntheticDeviceSvc, err := services.NewSyntheticWalletInstanceService(settings) if err != nil { logger.Error().Err(err).Msg("unable to create Synthetic Device service") } diff --git a/internal/services/registry/client.go b/internal/services/registry/client.go index 7fc65a11e..c84a5fb25 100644 --- a/internal/services/registry/client.go +++ b/internal/services/registry/client.go @@ -275,6 +275,21 @@ func (c *Client) BurnSyntheticDeviceSign(requestID string, vehicleNode, syntheti return c.sendRequest(requestID, data) } +// function mintVehicleAndSdSign(MintVehicleAndSdInput calldata data) +func (c *Client) MintVehicleAndSDign(requestID string, data contracts.MintVehicleAndSdInput) error { + abi, err := contracts.RegistryMetaData.GetAbi() + if err != nil { + return err + } + + data_, err := abi.Pack("mintVehicleAndSdSign", data) + if err != nil { + return err + } + + return c.sendRequest(requestID, data_) +} + func (c *Client) sendRequest(requestID string, data []byte) error { event := shared.CloudEvent[RequestData]{ ID: ksuid.New().String(), diff --git a/internal/services/synthetic_device_instance_service.go b/internal/services/synthetic_device_instance_service.go index 023af9b13..ca7cd35ed 100644 --- a/internal/services/synthetic_device_instance_service.go +++ b/internal/services/synthetic_device_instance_service.go @@ -4,7 +4,6 @@ import ( "context" "github.com/DIMO-Network/devices-api/internal/config" - "github.com/DIMO-Network/shared/db" pb "github.com/DIMO-Network/synthetic-wallet-instance/pkg/grpc" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -16,39 +15,22 @@ type SyntheticWalletInstanceService interface { } type syntheticWalletInstanceService struct { - dbs func() *db.ReaderWriter - grpc *grpcClient -} - -type grpcClient struct { client pb.SyntheticWalletClient - conn *grpc.ClientConn } -func NewSyntheticWalletInstanceService(DBS func() *db.ReaderWriter, settings *config.Settings) (SyntheticWalletInstanceService, error) { +func NewSyntheticWalletInstanceService(settings *config.Settings) (SyntheticWalletInstanceService, error) { conn, err := grpc.Dial(settings.SyntheticWalletGRPCAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { return nil, err } - syntheticDeviceClient := pb.NewSyntheticWalletClient(conn) - - grpc := &grpcClient{ - conn: conn, - client: syntheticDeviceClient, - } - - return &syntheticWalletInstanceService{ - dbs: DBS, - grpc: grpc, - }, nil + return &syntheticWalletInstanceService{client: pb.NewSyntheticWalletClient(conn)}, nil } func (v *syntheticWalletInstanceService) GetAddress(ctx context.Context, childNumber uint32) ([]byte, error) { - res, err := v.grpc.client.GetAddress(ctx, &pb.GetAddressRequest{ + res, err := v.client.GetAddress(ctx, &pb.GetAddressRequest{ ChildNumber: childNumber, }) - if err != nil { return nil, err } @@ -57,11 +39,10 @@ func (v *syntheticWalletInstanceService) GetAddress(ctx context.Context, childNu } func (v *syntheticWalletInstanceService) SignHash(ctx context.Context, childNumber uint32, hash []byte) ([]byte, error) { - res, err := v.grpc.client.SignHash(ctx, &pb.SignHashRequest{ + res, err := v.client.SignHash(ctx, &pb.SignHashRequest{ ChildNumber: childNumber, Hash: hash, }) - if err != nil { return nil, err } From 43d5b2765a4087708a81ea49c4933d7df502c573 Mon Sep 17 00:00:00 2001 From: Dylan Moreland Date: Mon, 24 Jul 2023 16:20:13 -0400 Subject: [PATCH 03/11] More wiring --- cmd/devices-api/api.go | 2 +- internal/controllers/synthetic_devices_controller.go | 4 ++++ internal/controllers/synthetic_devices_controller_test.go | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cmd/devices-api/api.go b/cmd/devices-api/api.go index ee6772551..a0e348ec2 100644 --- a/cmd/devices-api/api.go +++ b/cmd/devices-api/api.go @@ -253,7 +253,7 @@ func startWebAPI(logger zerolog.Logger, settings *config.Settings, pdb db.Store, logger.Error().Err(err).Msg("unable to create Synthetic Device service") } - syntheticController := controllers.NewSyntheticDevicesController(settings, pdb.DBS, &logger, ddSvc, usersClient, syntheticDeviceSvc, registryClient, smartcarClient, teslaSvc, cipher) + syntheticController := controllers.NewSyntheticDevicesController(settings, pdb.DBS, &logger, ddSvc, usersClient, syntheticDeviceSvc, registryClient, smartcarClient, teslaSvc, cipher, scTaskSvc, teslaTaskService) sdAuth := v1Auth.Group("/synthetic/device") diff --git a/internal/controllers/synthetic_devices_controller.go b/internal/controllers/synthetic_devices_controller.go index 952a8d102..159044eba 100644 --- a/internal/controllers/synthetic_devices_controller.go +++ b/internal/controllers/synthetic_devices_controller.go @@ -86,6 +86,8 @@ func NewSyntheticDevicesController( smartcarClient services.SmartcarClient, teslaSvc services.TeslaService, cipher shared.Cipher, + smartcarTask services.SmartcarTaskService, + teslaTask services.TeslaTaskService, ) SyntheticDevicesController { return SyntheticDevicesController{ Settings: settings, @@ -98,6 +100,8 @@ func NewSyntheticDevicesController( smartcarClient: smartcarClient, teslaService: teslaSvc, cipher: cipher, + teslaTask: teslaTask, + smartcarTask: smartcarTask, } } diff --git a/internal/controllers/synthetic_devices_controller_test.go b/internal/controllers/synthetic_devices_controller_test.go index 46df6d073..0a85f1f02 100644 --- a/internal/controllers/synthetic_devices_controller_test.go +++ b/internal/controllers/synthetic_devices_controller_test.go @@ -108,7 +108,7 @@ func (s *SyntheticDevicesControllerTestSuite) SetupTest() { logger := test.Logger() - c := NewSyntheticDevicesController(mockSettings, s.pdb.DBS, logger, s.deviceDefSvc, s.userClient, s.syntheticDeviceSigSvc, client, s.smartcarClient, s.teslaService, new(shared.ROT13Cipher)) + c := NewSyntheticDevicesController(mockSettings, s.pdb.DBS, logger, s.deviceDefSvc, s.userClient, s.syntheticDeviceSigSvc, client, s.smartcarClient, s.teslaService, new(shared.ROT13Cipher), nil, nil) s.sdc = c app := test.SetupAppFiber(*logger) From 7f7e7e2d7debb3951d5d72a0770ada457bc55c81 Mon Sep 17 00:00:00 2001 From: Dylan Moreland Date: Mon, 24 Jul 2023 19:42:45 -0400 Subject: [PATCH 04/11] You can't stop progress --- cmd/devices-api/api.go | 37 +- .../device_data_controller_test.go | 20 +- .../synthetic_devices_controller.go | 583 ++---------- .../synthetic_devices_controller_test.go | 863 +++++++++--------- .../controllers/user_devices_controller.go | 82 ++ .../user_devices_controller_test.go | 2 +- .../user_integrations_controller_test.go | 18 +- internal/services/registry/client.go | 26 +- internal/services/registry/storage.go | 21 + 9 files changed, 651 insertions(+), 1001 deletions(-) diff --git a/cmd/devices-api/api.go b/cmd/devices-api/api.go index a0e348ec2..d3a2154b4 100644 --- a/cmd/devices-api/api.go +++ b/cmd/devices-api/api.go @@ -118,8 +118,16 @@ func startWebAPI(logger zerolog.Logger, settings *config.Settings, pdb db.Store, KeyPrefix: "devices-api", }) + var wallet services.SyntheticWalletInstanceService + if settings.SyntheticDevicesEnabled { + wallet, err = services.NewSyntheticWalletInstanceService(settings) + if err != nil { + logger.Fatal().Err(err).Msg("Couldn't construct wallet client.") + } + } + // controllers - userDeviceController := controllers.NewUserDevicesController(settings, pdb.DBS, &logger, ddSvc, ddIntSvc, eventService, smartcarClient, scTaskSvc, teslaSvc, teslaTaskService, cipher, autoPiSvc, services.NewNHTSAService(), autoPiIngest, deviceDefinitionRegistrar, autoPiTaskService, producer, s3NFTServiceClient, autoPi, redisCache, openAI, usersClient, ddaSvc, natsSvc) + userDeviceController := controllers.NewUserDevicesController(settings, pdb.DBS, &logger, ddSvc, ddIntSvc, eventService, smartcarClient, scTaskSvc, teslaSvc, teslaTaskService, cipher, autoPiSvc, services.NewNHTSAService(), autoPiIngest, deviceDefinitionRegistrar, autoPiTaskService, producer, s3NFTServiceClient, autoPi, redisCache, openAI, usersClient, ddaSvc, natsSvc, wallet) geofenceController := controllers.NewGeofencesController(settings, pdb.DBS, &logger, producer, ddSvc) webhooksController := controllers.NewWebhooksController(settings, pdb.DBS, &logger, autoPiSvc, ddIntSvc) documentsController := controllers.NewDocumentsController(settings, &logger, s3ServiceClient, pdb.DBS) @@ -247,25 +255,6 @@ func startWebAPI(logger zerolog.Logger, settings *config.Settings, pdb db.Store, v1Auth.Delete("/documents/:id", documentsController.DeleteDocument) v1Auth.Get("/documents/:id/download", documentsController.DownloadDocument) - if settings.SyntheticDevicesEnabled { - syntheticDeviceSvc, err := services.NewSyntheticWalletInstanceService(settings) - if err != nil { - logger.Error().Err(err).Msg("unable to create Synthetic Device service") - } - - syntheticController := controllers.NewSyntheticDevicesController(settings, pdb.DBS, &logger, ddSvc, usersClient, syntheticDeviceSvc, registryClient, smartcarClient, teslaSvc, cipher, scTaskSvc, teslaTaskService) - - sdAuth := v1Auth.Group("/synthetic/device") - - sdAuth.Get("/mint/:integrationNode/:vehicleNode", syntheticController.GetSyntheticDeviceMintingPayload) - sdAuth.Post("/mint/:integrationNode/:vehicleNode", syntheticController.MintSyntheticDevice) - - sdAuth.Get("/:syntheticDeviceNode/burn", syntheticController.GetSyntheticDeviceBurnPayload) - sdAuth.Post("/:syntheticDeviceNode/burn", syntheticController.BurnSyntheticDevice) - - sdAuth.Post("/:syntheticDeviceNode/re-authenticate", syntheticController.ReAuthenticate) - } - // Vehicle owner routes. udOwnerMw := owner.UserDevice(pdb, usersClient, &logger) udOwner := v1Auth.Group("/user/devices/:userDeviceID", udOwnerMw) @@ -295,6 +284,13 @@ func startWebAPI(logger zerolog.Logger, settings *config.Settings, pdb db.Store, udOwner.Post("/integrations/:integrationID", userDeviceController.RegisterDeviceIntegration) udOwner.Post("/commands/refresh", userDeviceController.RefreshUserDeviceStatus) + if settings.SyntheticDevicesEnabled { + syntheticController := controllers.NewSyntheticDevicesController(settings, pdb.DBS, &logger, ddSvc, usersClient, wallet, registryClient) + + udOwner.Get("/integrations/:integrationID/commands/mint", syntheticController.GetSyntheticDeviceMintingPayload) + udOwner.Post("/integrations/:integrationID/commands/mint", syntheticController.MintSyntheticDevice) + } + // Vehicle commands. udOwner.Post("/integrations/:integrationID/commands/doors/unlock", userDeviceController.UnlockDoors) udOwner.Post("/integrations/:integrationID/commands/doors/lock", userDeviceController.LockDoors) @@ -305,6 +301,7 @@ func startWebAPI(logger zerolog.Logger, settings *config.Settings, pdb db.Store, udOwner.Post("/commands/opt-in", userDeviceController.DeviceOptIn) // AftermarketDevice pairing and unpairing. + // Routes are transitioning from /autopi to /aftermarket udOwner.Get("/autopi/commands/pair", userDeviceController.GetAutoPiPairMessage) udOwner.Get("/aftermarket/commands/pair", userDeviceController.GetAutoPiPairMessage) udOwner.Post("/autopi/commands/pair", userDeviceController.PostPairAutoPi) diff --git a/internal/controllers/device_data_controller_test.go b/internal/controllers/device_data_controller_test.go index 6de154009..c7823295f 100644 --- a/internal/controllers/device_data_controller_test.go +++ b/internal/controllers/device_data_controller_test.go @@ -62,7 +62,7 @@ func TestUserDevicesController_calculateRange(t *testing.T) { DeviceAttributes: attrs, }, nil) - _ = NewUserDevicesController(&config.Settings{Port: "3000"}, nil, &logger, deviceDefSvc, nil, &fakeEventService{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + _ = NewUserDevicesController(&config.Settings{Port: "3000"}, nil, &logger, deviceDefSvc, nil, &fakeEventService{}, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) rge, err := calculateRange(ctx, deviceDefSvc, ddID, styleID, .7) require.NoError(t, err) require.NotNil(t, rge) @@ -144,7 +144,7 @@ func TestUserDevicesController_GetUserDeviceStatus(t *testing.T) { }() testUserID := "123123" - c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, mockDeps.deviceDataSvc, nil) + c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, mockDeps.deviceDataSvc, nil, nil) app := fiber.New() app.Get("/user/devices/:userDeviceID/status", test.AuthInjectorTestHandler(testUserID), c.GetUserDeviceStatus) @@ -197,7 +197,7 @@ func TestUserDevicesController_QueryDeviceErrorCodes(t *testing.T) { }() testUserID := "123123" - c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, nil, nil) + c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, nil, nil, nil) app := fiber.New() app.Post("/user/devices/:userDeviceID/error-codes", test.AuthInjectorTestHandler(testUserID), c.QueryDeviceErrorCodes) @@ -271,7 +271,7 @@ func TestUserDevicesController_ShouldErrorOnTooManyErrorCodes(t *testing.T) { }() testUserID := "123123" - c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, nil, nil) + c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, nil, nil, nil) app := fiber.New() app.Post("/user/devices/:userDeviceID/error-codes", test.AuthInjectorTestHandler(testUserID), c.QueryDeviceErrorCodes) @@ -344,7 +344,7 @@ func TestUserDevicesController_ShouldErrorInvalidErrorCodes(t *testing.T) { }() testUserID := "123123" - c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, nil, nil) + c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, nil, nil, nil) app := fiber.New() app.Post("/user/devices/:userDeviceID/error-codes", test.AuthInjectorTestHandler(testUserID), c.QueryDeviceErrorCodes) @@ -413,7 +413,7 @@ func TestUserDevicesController_ShouldErrorOnEmptyErrorCodes(t *testing.T) { }() testUserID := "123123" - c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, nil, nil) + c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, nil, nil, nil) app := fiber.New() app.Post("/user/devices/:userDeviceID/error-codes", test.AuthInjectorTestHandler(testUserID), c.QueryDeviceErrorCodes) @@ -482,7 +482,7 @@ func TestUserDevicesController_ShouldStoreErrorCodeResponse(t *testing.T) { }() testUserID := "123123" - c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, nil, nil) + c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, nil, nil, nil) app := fiber.New() app.Post("/user/devices/:userDeviceID/error-codes", test.AuthInjectorTestHandler(testUserID), c.QueryDeviceErrorCodes) @@ -567,7 +567,7 @@ func TestUserDevicesController_GetUserDevicesErrorCodeQueries(t *testing.T) { }() testUserID := "123123" - c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, nil, nil) + c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, nil, nil, nil) app := fiber.New() app.Get("/user/devices/:userDeviceID/error-codes", test.AuthInjectorTestHandler(testUserID), c.GetUserDeviceErrorCodeQueries) @@ -643,7 +643,7 @@ func TestUserDevicesController_ClearUserDeviceErrorCodeQuery(t *testing.T) { }() testUserID := "123123" - c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, nil, nil) + c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, nil, nil, nil) app := fiber.New() app.Post("/user/devices/:userDeviceID/error-codes/clear", test.AuthInjectorTestHandler(testUserID), c.ClearUserDeviceErrorCodeQuery) @@ -730,7 +730,7 @@ func TestUserDevicesController_ErrorOnAllErrorCodesCleared(t *testing.T) { }() testUserID := "123123" - c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, nil, nil) + c := NewUserDevicesController(&config.Settings{Port: "3000"}, pdb.DBS, &mockDeps.logger, mockDeps.deviceDefSvc, mockDeps.deviceDefIntSvc, &fakeEventService{}, mockDeps.scClient, mockDeps.scTaskSvc, mockDeps.teslaSvc, mockDeps.teslaTaskService, nil, nil, mockDeps.nhtsaService, mockDeps.autoPiIngest, mockDeps.deviceDefinitionIngest, mockDeps.autoPiTaskSvc, nil, nil, nil, nil, mockDeps.openAISvc, nil, nil, nil, nil) app := fiber.New() app.Post("/user/devices/:userDeviceID/error-codes/clear", test.AuthInjectorTestHandler(testUserID), c.ClearUserDeviceErrorCodeQuery) diff --git a/internal/controllers/synthetic_devices_controller.go b/internal/controllers/synthetic_devices_controller.go index 159044eba..f9dcd85fd 100644 --- a/internal/controllers/synthetic_devices_controller.go +++ b/internal/controllers/synthetic_devices_controller.go @@ -2,15 +2,9 @@ package controllers import ( "context" - "database/sql" - "encoding/json" - "errors" "fmt" "math/big" - "strconv" - "time" - "github.com/DIMO-Network/device-definitions-api/pkg/grpc" "github.com/DIMO-Network/devices-api/internal/config" "github.com/DIMO-Network/devices-api/internal/constants" "github.com/DIMO-Network/devices-api/internal/contracts" @@ -18,7 +12,6 @@ import ( "github.com/DIMO-Network/devices-api/internal/services" "github.com/DIMO-Network/devices-api/internal/services/registry" "github.com/DIMO-Network/devices-api/models" - "github.com/DIMO-Network/shared" pb "github.com/DIMO-Network/shared/api/users" "github.com/DIMO-Network/shared/db" "github.com/ericlagergren/decimal" @@ -28,8 +21,6 @@ import ( "github.com/gofiber/fiber/v2" "github.com/rs/zerolog" "github.com/segmentio/ksuid" - smartcar "github.com/smartcar/go-sdk" - "github.com/volatiletech/null/v8" "github.com/volatiletech/sqlboiler/v4/boil" "github.com/volatiletech/sqlboiler/v4/queries" "github.com/volatiletech/sqlboiler/v4/queries/qm" @@ -44,31 +35,10 @@ type SyntheticDevicesController struct { usersClient pb.UserServiceClient walletSvc services.SyntheticWalletInstanceService registryClient registry.Client - - cipher shared.Cipher - - smartcarClient services.SmartcarClient - smartcarTask services.SmartcarTaskService - - teslaService services.TeslaService - teslaTask services.TeslaTaskService } type MintSyntheticDeviceRequest struct { - Credentials credentials `json:"credentials"` - OwnerSignature string `json:"ownerSignature"` -} - -type credentials struct { - // Smartcar - Code string `json:"code"` - RedirectURI string `json:"redirectUri"` - - // Tesla - ID string `json:"id"` - AccessToken string `json:"accessToken"` - RefreshToken string `json:"refreshToken"` - ExpiresIn int64 `json:"expiresIn"` + Signature string `json:"signature"` } type SyntheticDeviceSequence struct { @@ -83,11 +53,6 @@ func NewSyntheticDevicesController( usersClient pb.UserServiceClient, walletSvc services.SyntheticWalletInstanceService, registryClient registry.Client, - smartcarClient services.SmartcarClient, - teslaSvc services.TeslaService, - cipher shared.Cipher, - smartcarTask services.SmartcarTaskService, - teslaTask services.TeslaTaskService, ) SyntheticDevicesController { return SyntheticDevicesController{ Settings: settings, @@ -97,11 +62,6 @@ func NewSyntheticDevicesController( deviceDefSvc: deviceDefSvc, walletSvc: walletSvc, registryClient: registryClient, - smartcarClient: smartcarClient, - teslaService: teslaSvc, - cipher: cipher, - teslaTask: teslaTask, - smartcarTask: smartcarTask, } } @@ -134,108 +94,58 @@ func (sdc *SyntheticDevicesController) getEIP712Mint(integrationID, vehicleNode } } -func (sdc *SyntheticDevicesController) getEIP712Burn(vehicleNode, syntheticDeviceNode int64) *signer.TypedData { - return &signer.TypedData{ - Types: signer.Types{ - "EIP712Domain": []signer.Type{ - {Name: "name", Type: "string"}, - {Name: "version", Type: "string"}, - {Name: "chainId", Type: "uint256"}, - {Name: "verifyingContract", Type: "address"}, - }, - "BurnSyntheticDeviceSign": []signer.Type{ - {Name: "vehicleNode", Type: "uint256"}, - {Name: "syntheticDeviceNode", Type: "uint256"}, - }, - }, - PrimaryType: "BurnSyntheticDeviceSign", - Domain: signer.TypedDataDomain{ - Name: "DIMO", - Version: "1", - ChainId: math.NewHexOrDecimal256(sdc.Settings.DIMORegistryChainID), - VerifyingContract: sdc.Settings.DIMORegistryAddr, - }, - Message: signer.TypedDataMessage{ - "vehicleNode": math.NewHexOrDecimal256(vehicleNode), - "syntheticDeviceNode": math.NewHexOrDecimal256(syntheticDeviceNode), - }, - } -} - -type BurnSyntheticDeviceRequest struct { - OwnerSignature string `json:"ownerSignature"` -} - -func (sdc *SyntheticDevicesController) verifyUserAddressAndNFTExist(ctx context.Context, user *pb.User, vehicleNode int64) (*models.VehicleNFT, error) { - if user.EthereumAddress == nil { - return nil, fiber.NewError(fiber.StatusUnauthorized, "User does not have an Ethereum address.") - } - - uadd := common.HexToAddress(*user.EthereumAddress) - - vnID := types.NewNullDecimal(decimal.New(vehicleNode, 0)) - vehicleNFT, err := models.VehicleNFTS(models.VehicleNFTWhere.TokenID.EQ(vnID)).One(ctx, sdc.DBS().Reader) - if err != nil { - if err == sql.ErrNoRows { - return nil, fiber.NewError(fiber.StatusNotFound, "No vehicle with that id found.") - } - return nil, err - } - - vown := common.BytesToAddress(vehicleNFT.OwnerAddress.Bytes) - if uadd != vown { - return nil, fiber.NewError(fiber.StatusForbidden, fmt.Sprintf("Vehicle owned by another address, %s.", vown)) - } - - if !vehicleNFT.UserDeviceID.Valid { - return nil, fiber.NewError(fiber.StatusConflict, "Vehicle deleted.") - } - - return vehicleNFT, nil -} - // GetSyntheticDeviceMintingPayload godoc // @Description Produces the payload that the user signs and submits to mint a synthetic device for // @Description the given vehicle and integration. // @Tags integrations // @Produce json -// @Param integrationNode path int true "token ID" -// @Param vehicleNode path int true "vehicle ID" +// @Param userDeviceID path int true "user device KSUID" +// @Param integrationID path int true "integration KSUD, must be software-based" // @Success 200 {array} signer.TypedData -// @Router /synthetic/device/mint/{integrationNode}/{vehicleNode} [get] +// @Router /user/devices/{userDeviceID}/integrations/{integrationID}/commands/mint [get] func (sdc *SyntheticDevicesController) GetSyntheticDeviceMintingPayload(c *fiber.Ctx) error { - rawIntegrationNode := c.Params("integrationNode") - vehicleNode := c.Params("vehicleNode") - userID := helpers.GetUserID(c) - - integrationNode, err := strconv.ParseUint(rawIntegrationNode, 10, 64) + userDeviceID := c.Params("userDeviceID") + integrationID := c.Params("integrationID") + ud, err := models.UserDevices( + models.UserDeviceWhere.ID.EQ(userDeviceID), + qm.Load(qm.Rels(models.UserDeviceRels.VehicleNFT, models.VehicleNFTRels.VehicleTokenSyntheticDevices)), + qm.Load(models.UserDeviceRels.UserDeviceAPIIntegrations, models.UserDeviceAPIIntegrationWhere.IntegrationID.EQ(integrationID)), + ).One(c.Context(), sdc.DBS().Reader) if err != nil { - return fiber.NewError(fiber.StatusBadRequest, "invalid integrationNode provided") + return err } - user, err := sdc.usersClient.GetUser(c.Context(), &pb.GetUserRequest{ - Id: userID, - }) - if err != nil { - sdc.log.Debug().Err(err).Msg("error occurred when fetching user") - return helpers.GrpcErrorToFiber(err, "error occurred when fetching user") + if ud.R.VehicleNFT == nil || ud.R.VehicleNFT.TokenID.IsZero() { + return fiber.NewError(fiber.StatusConflict, "Vehicle not minted.") } - vid, err := strconv.ParseInt(vehicleNode, 10, 64) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, "invalid vehicleNode provided") + if ud.R.VehicleNFT.R.VehicleTokenSyntheticDevices != nil { + return fiber.NewError(fiber.StatusConflict, "Vehicle already paired with a synthetic device.") } - if _, err := sdc.verifyUserAddressAndNFTExist(c.Context(), user, vid); err != nil { - return err + if len(ud.R.UserDeviceAPIIntegrations) == 0 { + return fiber.NewError(fiber.StatusConflict, "Vehicle does not have this kind of connection.") } - integration, err := sdc.deviceDefSvc.GetIntegrationByTokenID(c.Context(), integrationNode) + in, err := sdc.deviceDefSvc.GetIntegrationByID(c.Context(), integrationID) if err != nil { return helpers.GrpcErrorToFiber(err, "failed to get integration") } - response := sdc.getEIP712Mint(int64(integration.TokenId), vid) + if in.Vendor != constants.SmartCarVendor && in.Vendor != constants.TeslaVendor { + return fiber.NewError(fiber.StatusConflict, "This is not a software connection.") + } + + if in.TokenId == 0 { + return fiber.NewError(fiber.StatusConflict, "Connection type not yet minted.") + } + + vid, ok := ud.R.VehicleNFT.TokenID.Int64() + if !ok { + return fmt.Errorf("vehicle token id invalid, this should never happen %d", ud.R.VehicleNFT.TokenID) + } + + response := sdc.getEIP712Mint(int64(in.TokenId), vid) return c.JSON(response) } @@ -244,54 +154,70 @@ func (sdc *SyntheticDevicesController) GetSyntheticDeviceMintingPayload(c *fiber // @Description Submit a metadata // @Tags integrations // @Produce json -// @Param integrationNode path int true "token ID" -// @Param vehicleNode path int true "vehicle ID" +// @Param userDeviceID path int true "user device KSUID, must be minted" +// @Param integrationID path int true "integration KSUD, must be software-based" // @Success 204 -// @Router /synthetic/device/mint/{integrationNode}/{vehicleNode} [post] +// @Router /user/devices/{userDeviceID}/integrations/{integrationID}/commands/mint [post] func (sdc *SyntheticDevicesController) MintSyntheticDevice(c *fiber.Ctx) error { - rawIntegrationNode := c.Params("integrationNode") - vehicleNode := c.Params("vehicleNode") - userID := helpers.GetUserID(c) - req := &MintSyntheticDeviceRequest{} - if err := c.BodyParser(req); err != nil { - return fiber.NewError(fiber.StatusBadRequest, "Couldn't parse request.") - } + userDeviceID := c.Params("userDeviceID") + integrationID := c.Params("integrationID") - integrationNode, err := strconv.ParseUint(rawIntegrationNode, 10, 64) + ud, err := models.UserDevices( + models.UserDeviceWhere.ID.EQ(userDeviceID), + qm.Load(qm.Rels(models.UserDeviceRels.VehicleNFT, models.VehicleNFTRels.VehicleTokenSyntheticDevices)), + qm.Load(models.UserDeviceRels.UserDeviceAPIIntegrations, models.UserDeviceAPIIntegrationWhere.IntegrationID.EQ(integrationID)), + ).One(c.Context(), sdc.DBS().Reader) if err != nil { - return fiber.NewError(fiber.StatusBadRequest, "invalid integrationNode provided") + return err + } + + if ud.R.VehicleNFT == nil || ud.R.VehicleNFT.TokenID.IsZero() { + return fiber.NewError(fiber.StatusConflict, "Vehicle not minted.") + } + + if ud.R.VehicleNFT.R.VehicleTokenSyntheticDevices != nil { + return fiber.NewError(fiber.StatusConflict, "Vehicle already paired with a synthetic device.") } - integration, err := sdc.deviceDefSvc.GetIntegrationByTokenID(c.Context(), integrationNode) + if len(ud.R.UserDeviceAPIIntegrations) == 0 { + return fiber.NewError(fiber.StatusConflict, "Vehicle does not have this kind of connection.") + } + + in, err := sdc.deviceDefSvc.GetIntegrationByID(c.Context(), integrationID) if err != nil { return helpers.GrpcErrorToFiber(err, "failed to get integration") } - if integration.Vendor == constants.TeslaVendor && req.Credentials.AccessToken == "" { - return fiber.NewError(fiber.StatusBadRequest, "invalid access token") + if in.Vendor != constants.SmartCarVendor && in.Vendor != constants.TeslaVendor { + return fiber.NewError(fiber.StatusConflict, "This is not a software connection.") } - if integration.Vendor == constants.SmartCarVendor && req.Credentials.Code == "" { - return fiber.NewError(fiber.StatusBadRequest, "invalid authorization code") + if in.TokenId == 0 { + return fiber.NewError(fiber.StatusConflict, "Connection type not yet minted.") } - user, err := sdc.usersClient.GetUser(c.Context(), &pb.GetUserRequest{Id: userID}) - if err != nil { - return helpers.GrpcErrorToFiber(err, "error occurred when fetching user") + vid, ok := ud.R.VehicleNFT.TokenID.Int64() + if !ok { + return fmt.Errorf("vehicle token id invalid, this should never happen %d", ud.R.VehicleNFT.TokenID) } - vid, err := strconv.ParseInt(vehicleNode, 10, 64) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, "invalid vehicle id provided") + userID := helpers.GetUserID(c) + var req MintSyntheticDeviceRequest + if err := c.BodyParser(&req); err != nil { + return fiber.NewError(fiber.StatusBadRequest, "Couldn't parse request.") } - vNFT, err := sdc.verifyUserAddressAndNFTExist(c.Context(), user, vid) + user, err := sdc.usersClient.GetUser(c.Context(), &pb.GetUserRequest{Id: userID}) if err != nil { - return err + return helpers.GrpcErrorToFiber(err, "error occurred when fetching user") + } + + if user.EthereumAddress == nil { + return fiber.NewError(fiber.StatusConflict, "User does not have an Ethereum address.") } userAddr := common.HexToAddress(*user.EthereumAddress) - rawPayload := sdc.getEIP712Mint(int64(integration.TokenId), vid) + rawPayload := sdc.getEIP712Mint(int64(in.TokenId), vid) tdHash, _, err := signer.TypedDataAndHash(*rawPayload) if err != nil { @@ -299,7 +225,7 @@ func (sdc *SyntheticDevicesController) MintSyntheticDevice(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "Couldn't verify signature.") } - ownerSignature := common.FromHex(req.OwnerSignature) + ownerSignature := common.FromHex(req.Signature) recAddr, err := helpers.Ecrecover(tdHash, ownerSignature) if err != nil { sdc.log.Err(err).Msg("unable to validate signature") @@ -310,11 +236,6 @@ func (sdc *SyntheticDevicesController) MintSyntheticDevice(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "Invalid signature.") } - udai, err := sdc.generateUDAI(c.Context(), req.Credentials, vNFT.UserDeviceID.String, integration) - if err != nil { - return err - } - childKeyNumber, err := sdc.generateNextChildKeyNumber(c.Context()) if err != nil { sdc.log.Err(err).Msg("failed to generate sequence from database") @@ -323,7 +244,7 @@ func (sdc *SyntheticDevicesController) MintSyntheticDevice(c *fiber.Ctx) error { requestID := ksuid.New().String() - syntheticDeviceAddr, err := sdc.sendSyntheticDeviceMintPayload(c.Context(), requestID, tdHash, int(vid), integration.TokenId, ownerSignature, childKeyNumber) + syntheticDeviceAddr, err := sdc.sendSyntheticDeviceMintPayload(c.Context(), requestID, tdHash, int(vid), in.TokenId, ownerSignature, childKeyNumber) if err != nil { sdc.log.Err(err).Msg("synthetic device minting request failed") return fiber.NewError(fiber.StatusInternalServerError, "synthetic device minting request failed") @@ -334,10 +255,6 @@ func (sdc *SyntheticDevicesController) MintSyntheticDevice(c *fiber.Ctx) error { return err } - if err := udai.Insert(c.Context(), tx, boil.Infer()); err != nil { - return err - } - metaReq := &models.MetaTransactionRequest{ ID: requestID, Status: models.MetaTransactionRequestStatusUnsubmitted, @@ -350,7 +267,7 @@ func (sdc *SyntheticDevicesController) MintSyntheticDevice(c *fiber.Ctx) error { syntheticDevice := &models.SyntheticDevice{ VehicleTokenID: types.NewNullDecimal(decimal.New(vid, 0)), - IntegrationTokenID: types.NewDecimal(decimal.New(int64(integrationNode), 0)), + IntegrationTokenID: types.NewDecimal(decimal.New(int64(in.TokenId), 0)), WalletChildNumber: childKeyNumber, WalletAddress: syntheticDeviceAddr, MintRequestID: requestID, @@ -411,347 +328,3 @@ func (sdc *SyntheticDevicesController) generateNextChildKeyNumber(ctx context.Co return seq.NextVal, nil } - -func (sdc *SyntheticDevicesController) generateUDAI(ctx context.Context, creds credentials, userDeviceID string, integration *grpc.Integration) (*models.UserDeviceAPIIntegration, error) { - udi := models.UserDeviceAPIIntegration{ - IntegrationID: integration.Id, - UserDeviceID: userDeviceID, - Status: models.UserDeviceAPIIntegrationStatusPending, - TaskID: null.StringFrom(ksuid.New().String()), - } - - switch integration.Vendor { - case constants.SmartCarVendor: - token, err := sdc.exchangeSmartCarCode(ctx, creds.Code, creds.RedirectURI) - if err != nil { - return nil, err - } - - encAccess, err := sdc.cipher.Encrypt(token.Access) - if err != nil { - return nil, opaqueInternalError - } - - encRefresh, err := sdc.cipher.Encrypt(token.Refresh) - if err != nil { - return nil, opaqueInternalError - } - - udi.AccessToken = null.StringFrom(encAccess) - udi.AccessExpiresAt = null.TimeFrom(token.AccessExpiry) - udi.RefreshToken = null.StringFrom(encRefresh) - - externalID, err := sdc.smartcarClient.GetExternalID(ctx, token.Access) - if err != nil { - return nil, err - } - - endpoints, err := sdc.smartcarClient.GetEndpoints(ctx, token.Access, externalID) - if err != nil { - sdc.log.Err(err).Msg("Failed to retrieve permissions from Smartcar.") - return nil, err - } - - meta := services.UserDeviceAPIIntegrationsMetadata{ - SmartcarEndpoints: endpoints, - } - - if doorControl, err := sdc.smartcarClient.HasDoorControl(ctx, token.Access, externalID); err != nil { - sdc.log.Err(err).Msg("Failed to retrieve door control permissions from Smartcar.") - return nil, err - } else if doorControl { - meta.Commands = &services.UserDeviceAPIIntegrationsMetadataCommands{ - Enabled: []string{"doors/unlock", "doors/lock"}, - } - } - - mb, _ := json.Marshal(meta) - udi.Metadata = null.JSONFrom(mb) - udi.ExternalID = null.StringFrom(externalID) - case constants.TeslaVendor: - teslaID, err := strconv.Atoi(creds.ID) - if err != nil { - sdc.log.Err(err).Msgf("unable to parse external id %q as integer", creds.ID) - return nil, err - } - - v, err := sdc.teslaService.GetVehicle(creds.AccessToken, teslaID) - if err != nil { - sdc.log.Err(err).Msg("unable to retrieve vehicle from Tesla") - return nil, err - } - - encAccess, err := sdc.cipher.Encrypt(creds.AccessToken) - if err != nil { - return nil, opaqueInternalError - } - encRefresh, err := sdc.cipher.Encrypt(creds.RefreshToken) - if err != nil { - return nil, opaqueInternalError - } - udi.AccessToken = null.StringFrom(encAccess) - udi.RefreshToken = null.StringFrom(encRefresh) - - meta := services.UserDeviceAPIIntegrationsMetadata{ - Commands: &services.UserDeviceAPIIntegrationsMetadataCommands{ - Enabled: []string{"doors/unlock", "doors/lock", "trunk/open", "frunk/open", "charge/limit"}, - }, - TeslaVehicleID: v.ID, - } - - mb, _ := json.Marshal(meta) - - udi.ExternalID = null.StringFrom(creds.ID) - udi.AccessExpiresAt = null.TimeFrom(time.Now().Add(time.Duration(creds.ExpiresIn) * time.Second)) - udi.Metadata = null.JSONFrom(mb) - default: - return nil, fmt.Errorf("unrecognized vendor %s", integration.Vendor) - } - - return &udi, nil -} - -func (sdc *SyntheticDevicesController) exchangeSmartCarCode(ctx context.Context, authCode, redirectURI string) (*smartcar.Token, error) { - token, err := sdc.smartcarClient.ExchangeCode(ctx, authCode, redirectURI) - if err != nil { - var scErr *services.SmartcarError - if errors.As(err, &scErr) { - sdc.log.Err(err).Str("function", "syntheticDeviceController.exchangeSmartCarCode").Msgf("Failed exchanging Authorization code. Status code %d, request id %s`.", scErr.Code, scErr.RequestID) - } else { - sdc.log.Err(err).Str("function", "syntheticDeviceController.exchangeSmartCarCode").Msg("Failed to exchange authorization code with Smartcar.") - } - - return nil, errors.New("failed to exchange authorization code with smartcar") - } - - return token, nil -} - -// GetSyntheticDeviceBurnPayload godoc -// @Description Produces the payload that the user signs and submits to burn a synthetic device. -// @Produce json -// @Param syntheticDeviceNode path int true "synthetic device token id" -// @Success 200 {array} signer.TypedData -// @Router /synthetic/device/{syntheticDeviceNode}/burn [get] -func (sdc *SyntheticDevicesController) GetSyntheticDeviceBurnPayload(c *fiber.Ctx) error { - syntheticDeviceNodeRaw := c.Params("syntheticDeviceNode") - userID := helpers.GetUserID(c) - - syntheticDeviceNode, err := strconv.ParseInt(syntheticDeviceNodeRaw, 10, 64) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Node id %q must be an integer.", syntheticDeviceNodeRaw)) - } - - sd, err := models.SyntheticDevices( - models.SyntheticDeviceWhere.TokenID.EQ(types.NewNullDecimal(decimal.New(syntheticDeviceNode, 0))), - qm.Load(models.SyntheticDeviceRels.VehicleToken), - ).One(c.Context(), sdc.DBS().Reader) - if err != nil { - if err == sql.ErrNoRows { - return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("No device with id %d found.", syntheticDeviceNode)) - } - return err - } - - vOwn := common.BytesToAddress(sd.R.VehicleToken.OwnerAddress.Bytes) - - user, err := sdc.usersClient.GetUser(c.Context(), &pb.GetUserRequest{Id: userID}) - if err != nil { - sdc.log.Debug().Err(err).Msg("error occurred when fetching user") - return helpers.GrpcErrorToFiber(err, "error occurred when fetching user") - } - - if user.EthereumAddress == nil { - return fiber.NewError(fiber.StatusForbidden, "No Ethereum address on file for user.") - } - - addr := common.HexToAddress(*user.EthereumAddress) - - if vOwn != addr { - return fiber.NewError(fiber.StatusForbidden, fmt.Sprintf("Vehicle is owned by %s, your address is %s.", vOwn, addr)) - } - - vehicleNode, _ := sd.VehicleTokenID.Int64() - - return c.JSON(sdc.getEIP712Burn(vehicleNode, syntheticDeviceNode)) -} - -// BurnSyntheticDevice godoc -// @Description Submit the signature required for the synthetic device burning meta-transaction. -// @Produce json -// @Param syntheticDeviceNode path int true "synthetic device token id" -// @Success 200 -// @Router /synthetic/device/{syntheticDeviceNode}/burn [post] -func (sdc *SyntheticDevicesController) BurnSyntheticDevice(c *fiber.Ctx) error { - syntheticDeviceNodeRaw := c.Params("syntheticDeviceNode") - userID := helpers.GetUserID(c) - - syntheticDeviceNode, err := strconv.ParseInt(syntheticDeviceNodeRaw, 10, 64) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Node id %q must be an integer.", syntheticDeviceNodeRaw)) - } - - sd, err := models.SyntheticDevices( - models.SyntheticDeviceWhere.TokenID.EQ(types.NewNullDecimal(decimal.New(syntheticDeviceNode, 0))), - qm.Load(models.SyntheticDeviceRels.VehicleToken), - ).One(c.Context(), sdc.DBS().Reader) - if err != nil { - if err == sql.ErrNoRows { - return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("No device with id %d found.", syntheticDeviceNode)) - } - return err - } - - vOwn := common.BytesToAddress(sd.R.VehicleToken.OwnerAddress.Bytes) - - user, err := sdc.usersClient.GetUser(c.Context(), &pb.GetUserRequest{Id: userID}) - if err != nil { - sdc.log.Debug().Err(err).Msg("error occurred when fetching user") - return helpers.GrpcErrorToFiber(err, "error occurred when fetching user") - } - - if user.EthereumAddress == nil { - return fiber.NewError(fiber.StatusForbidden, "No Ethereum address on file for user.") - } - - addr := common.HexToAddress(*user.EthereumAddress) - - if vOwn != addr { - return fiber.NewError(fiber.StatusForbidden, fmt.Sprintf("Vehicle is owned by %s, your address is %s.", vOwn, addr)) - } - - vehicleNode, _ := sd.VehicleTokenID.Int64() - - td := sdc.getEIP712Burn(vehicleNode, syntheticDeviceNode) - - var req BurnSyntheticDeviceRequest - if err := c.BodyParser(&req); err != nil { - return fiber.NewError(fiber.StatusBadRequest, "Couldn't parse request body.") - } - - ownerSignature := common.FromHex(req.OwnerSignature) - if len(ownerSignature) != 65 { - return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Owner signature was length %d, not 65.", len(ownerSignature))) - } - - hash, _, err := signer.TypedDataAndHash(*td) - if err != nil { - sdc.log.Err(err).Msg("Error occurred creating has of payload") - return fiber.NewError(fiber.StatusBadRequest, "Couldn't verify signature.") - } - - if recAddr, err := helpers.Ecrecover(hash, ownerSignature); err != nil { - return err - } else if recAddr != addr { - return fiber.NewError(fiber.StatusBadRequest, "Invalid signature.") - } - - reqID := ksuid.New().String() - - if err := sdc.registryClient.BurnSyntheticDeviceSign(reqID, big.NewInt(vehicleNode), big.NewInt(syntheticDeviceNode), ownerSignature); err != nil { - return err - } - - mtr := models.MetaTransactionRequest{ - ID: reqID, - Status: models.MetaTransactionRequestStatusUnsubmitted, - } - - if err := mtr.Insert(c.Context(), sdc.DBS().Writer, boil.Infer()); err != nil { - return err - } - - sd.BurnRequestID = null.StringFrom(reqID) - _, err = sd.Update(c.Context(), sdc.DBS().Writer, boil.Infer()) - - return err -} - -// ReAuthenticate godoc -// @Description Submit new credentials for the given synthetic device. Mostly -// @Description used in the event of an upstream password change. -// @Produce json -// @Param syntheticDeviceNode path int true "synthetic device token id" -// @Success 200 -// @Router /synthetic/device/{syntheticDeviceNode}/re-authenticate [post] -func (sdc *SyntheticDevicesController) ReAuthenticate(c *fiber.Ctx) error { - syntheticDeviceNodeRaw := c.Params("syntheticDeviceNode") - // userID := helpers.GetUserID(c) - - sdn, err := strconv.ParseInt(syntheticDeviceNodeRaw, 10, 64) - if err != nil { - return fiber.NewError(fiber.StatusBadRequest, "Couldn't parse the given token id.") - } - - sd, err := models.SyntheticDevices( - models.SyntheticDeviceWhere.TokenID.EQ(types.NewNullDecimal(decimal.New(sdn, 0))), - qm.Load(models.SyntheticDeviceRels.VehicleToken), - ).One(c.Context(), sdc.DBS().Reader) - if err != nil { - if err == sql.ErrNoRows { - return fiber.NewError(fiber.StatusNotFound, "No synthetic device with that id.") - } - return err - } - - if !sd.R.VehicleToken.UserDeviceID.Valid { - return fiber.NewError(fiber.StatusConflict, "Vehicle deleted.") - } - - iNode, _ := sd.IntegrationTokenID.Uint64() - - i, err := sdc.deviceDefSvc.GetIntegrationByTokenID(c.Context(), iNode) - if err != nil { - return err - } - - oldUDAI, err := models.FindUserDeviceAPIIntegration(c.Context(), sdc.DBS().Reader, sd.R.VehicleToken.UserDeviceID.String, i.Id) - if err != nil { - return err - } - - // Should really create a new type. - var req MintSyntheticDeviceRequest - if err := c.BodyParser(&req); err != nil { - return fiber.NewError(fiber.StatusBadRequest, "Couldn't parse request.") - } - - newUDAI, err := sdc.generateUDAI(c.Context(), req.Credentials, sd.R.VehicleToken.UserDeviceID.String, i) - if err != nil { - return err - } - - switch i.Vendor { - case constants.SmartCarVendor: - if err := sdc.smartcarTask.StopPoll(oldUDAI); err != nil { - return err - } - if err := sdc.smartcarTask.StartPoll(newUDAI); err != nil { - return err - } - if _, err := newUDAI.Update(c.Context(), sdc.DBS().Writer, boil.Infer()); err != nil { - return err - } - case constants.TeslaVendor: - // Awful - id, err := strconv.Atoi(newUDAI.ExternalID.String) - if err != nil { - return err - } - var md services.UserDeviceAPIIntegrationsMetadata - if err := newUDAI.Metadata.Unmarshal(&md); err != nil { - return err - } - if err := sdc.teslaTask.StopPoll(oldUDAI); err != nil { - return err - } - if err := sdc.teslaTask.StartPoll(&services.TeslaVehicle{ID: id, VehicleID: md.TeslaVehicleID}, newUDAI); err != nil { - return err - } - if _, err := newUDAI.Update(c.Context(), sdc.DBS().Writer, boil.Infer()); err != nil { - return err - } - } - - return nil -} diff --git a/internal/controllers/synthetic_devices_controller_test.go b/internal/controllers/synthetic_devices_controller_test.go index 0a85f1f02..46e47aa06 100644 --- a/internal/controllers/synthetic_devices_controller_test.go +++ b/internal/controllers/synthetic_devices_controller_test.go @@ -1,555 +1,510 @@ package controllers -import ( - "context" - "encoding/json" - "errors" - "fmt" - "io" - "math/big" - "testing" - "time" - - ddgrpc "github.com/DIMO-Network/device-definitions-api/pkg/grpc" - "github.com/DIMO-Network/devices-api/internal/config" - "github.com/DIMO-Network/devices-api/internal/constants" - "github.com/DIMO-Network/devices-api/internal/contracts" - "github.com/DIMO-Network/devices-api/internal/services" - mock_services "github.com/DIMO-Network/devices-api/internal/services/mocks" - "github.com/DIMO-Network/devices-api/internal/services/registry" - "github.com/DIMO-Network/devices-api/internal/test" - "github.com/DIMO-Network/devices-api/models" - "github.com/DIMO-Network/shared" - "github.com/DIMO-Network/shared/api/users" - "github.com/DIMO-Network/shared/db" - smock "github.com/Shopify/sarama/mocks" - "github.com/ericlagergren/decimal" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto/secp256k1" - "github.com/gofiber/fiber/v2" - "github.com/golang/mock/gomock" - "github.com/segmentio/ksuid" - smartcar "github.com/smartcar/go-sdk" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - "github.com/testcontainers/testcontainers-go" - "github.com/volatiletech/sqlboiler/v4/types" -) - -var signature = "0xa4438e5cb667dc63ebd694167ae3ad83585f2834c9b04895dd890f805c4c459a024ed9df1b03872536b4ac0c7720d02cb787884a093cfcde5c3bd7f94657e30c1b" -var userEthAddress = "0xd64E249A06ee6263d989e43aBFe12748a2506f88" -var mockProducer *smock.SyncProducer -var mockUserID = ksuid.New().String() -var mockSmartClientToken = &smartcar.Token{ - Access: "mockAccessToken", - AccessExpiry: time.Now().Add(time.Hour + 1), - Refresh: "mockRefreshToken", -} -var teslaClientToken = MintSyntheticDeviceRequest{ - Credentials: credentials{ - AccessToken: "accessToken", - RefreshToken: "refreshToken", - ID: "13", - ExpiresIn: 28800, - }, -} - -type SyntheticDevicesControllerTestSuite struct { - suite.Suite - pdb db.Store - container testcontainers.Container - ctx context.Context - mockCtrl *gomock.Controller - app *fiber.App - deviceDefSvc *mock_services.MockDeviceDefinitionService - userClient *mock_services.MockUserServiceClient - sdc SyntheticDevicesController - syntheticDeviceSigSvc *mock_services.MockSyntheticWalletInstanceService - smartcarClient *mock_services.MockSmartcarClient - teslaService *mock_services.MockTeslaService -} - -// SetupSuite starts container db -func (s *SyntheticDevicesControllerTestSuite) SetupSuite() { - s.ctx = context.Background() - s.pdb, s.container = test.StartContainerDatabase(s.ctx, s.T(), migrationsDirRelPath) -} - -func (s *SyntheticDevicesControllerTestSuite) SetupTest() { - s.mockCtrl = gomock.NewController(s.T()) - var err error - - s.deviceDefSvc = mock_services.NewMockDeviceDefinitionService(s.mockCtrl) - s.userClient = mock_services.NewMockUserServiceClient(s.mockCtrl) - s.syntheticDeviceSigSvc = mock_services.NewMockSyntheticWalletInstanceService(s.mockCtrl) - s.smartcarClient = mock_services.NewMockSmartcarClient(s.mockCtrl) - s.teslaService = mock_services.NewMockTeslaService(s.mockCtrl) - - mockProducer = smock.NewSyncProducer(s.T(), nil) - - mockSettings := &config.Settings{Port: "3000", DIMORegistryChainID: 80001, DIMORegistryAddr: common.HexToAddress("0x4De1bCf2B7E851E31216fC07989caA902A604784").Hex()} - mockSettings.DB.Name = "devices_api" - - client := registry.Client{ - Producer: mockProducer, - RequestTopic: "topic.transaction.request.send", - Contract: registry.Contract{ - ChainID: big.NewInt(mockSettings.DIMORegistryChainID), - Address: common.HexToAddress(mockSettings.DIMORegistryAddr), - Name: "DIMO", - Version: "1", - }, - } - - if err != nil { - s.T().Fatal(err) - } - - logger := test.Logger() - - c := NewSyntheticDevicesController(mockSettings, s.pdb.DBS, logger, s.deviceDefSvc, s.userClient, s.syntheticDeviceSigSvc, client, s.smartcarClient, s.teslaService, new(shared.ROT13Cipher), nil, nil) - s.sdc = c - - app := test.SetupAppFiber(*logger) - - app.Post("/v1/synthetic/device/mint/:integrationNode/:vehicleNode", test.AuthInjectorTestHandler(mockUserID), c.MintSyntheticDevice) - app.Get("/v1/synthetic/device/mint/:integrationNode/:vehicleNode", test.AuthInjectorTestHandler(mockUserID), c.GetSyntheticDeviceMintingPayload) - - s.app = app -} - -// TearDownTest after each test truncate tables -func (s *SyntheticDevicesControllerTestSuite) TearDownTest() { - test.TruncateTables(s.pdb.DBS().Writer.DB, s.T()) -} - -// TearDownSuite cleanup at end by terminating container -func (s *SyntheticDevicesControllerTestSuite) TearDownSuite() { - fmt.Printf("shutting down postgres at with session: %s \n", s.container.SessionID()) - - if err := s.container.Terminate(s.ctx); err != nil { - s.T().Fatal(err) - } - s.mockCtrl.Finish() -} - -// Test Runner -func TestSyntheticDevicesControllerTestSuite(t *testing.T) { - suite.Run(t, new(SyntheticDevicesControllerTestSuite)) -} - -func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload() { - _, addr, err := test.GenerateWallet() - assert.NoError(s.T(), err) - - email := "some@email.com" - eth := addr.Hex() +// var signature = "0xa4438e5cb667dc63ebd694167ae3ad83585f2834c9b04895dd890f805c4c459a024ed9df1b03872536b4ac0c7720d02cb787884a093cfcde5c3bd7f94657e30c1b" +// var userEthAddress = "0xd64E249A06ee6263d989e43aBFe12748a2506f88" +// var mockProducer *smock.SyncProducer +// var mockUserID = ksuid.New().String() +// var mockSmartClientToken = &smartcar.Token{ +// Access: "mockAccessToken", +// AccessExpiry: time.Now().Add(time.Hour + 1), +// Refresh: "mockRefreshToken", +// } + +// type SyntheticDevicesControllerTestSuite struct { +// suite.Suite +// pdb db.Store +// container testcontainers.Container +// ctx context.Context +// mockCtrl *gomock.Controller +// app *fiber.App +// deviceDefSvc *mock_services.MockDeviceDefinitionService +// userClient *mock_services.MockUserServiceClient +// sdc SyntheticDevicesController +// syntheticDeviceSigSvc *mock_services.MockSyntheticWalletInstanceService +// smartcarClient *mock_services.MockSmartcarClient +// teslaService *mock_services.MockTeslaService +// } + +// // SetupSuite starts container db +// func (s *SyntheticDevicesControllerTestSuite) SetupSuite() { +// s.ctx = context.Background() +// s.pdb, s.container = test.StartContainerDatabase(s.ctx, s.T(), migrationsDirRelPath) +// } + +// func (s *SyntheticDevicesControllerTestSuite) SetupTest() { +// s.mockCtrl = gomock.NewController(s.T()) +// var err error + +// s.deviceDefSvc = mock_services.NewMockDeviceDefinitionService(s.mockCtrl) +// s.userClient = mock_services.NewMockUserServiceClient(s.mockCtrl) +// s.syntheticDeviceSigSvc = mock_services.NewMockSyntheticWalletInstanceService(s.mockCtrl) +// s.smartcarClient = mock_services.NewMockSmartcarClient(s.mockCtrl) +// s.teslaService = mock_services.NewMockTeslaService(s.mockCtrl) + +// mockProducer = smock.NewSyncProducer(s.T(), nil) + +// mockSettings := &config.Settings{Port: "3000", DIMORegistryChainID: 80001, DIMORegistryAddr: common.HexToAddress("0x4De1bCf2B7E851E31216fC07989caA902A604784").Hex()} +// mockSettings.DB.Name = "devices_api" + +// client := registry.Client{ +// Producer: mockProducer, +// RequestTopic: "topic.transaction.request.send", +// Contract: registry.Contract{ +// ChainID: big.NewInt(mockSettings.DIMORegistryChainID), +// Address: common.HexToAddress(mockSettings.DIMORegistryAddr), +// Name: "DIMO", +// Version: "1", +// }, +// } + +// if err != nil { +// s.T().Fatal(err) +// } + +// logger := test.Logger() + +// c := NewSyntheticDevicesController(mockSettings, s.pdb.DBS, logger, s.deviceDefSvc, s.userClient, s.syntheticDeviceSigSvc, client) +// s.sdc = c + +// app := test.SetupAppFiber(*logger) + +// app.Post("/v1/synthetic/device/mint/:integrationNode/:vehicleNode", test.AuthInjectorTestHandler(mockUserID), c.MintSyntheticDevice) +// app.Get("/v1/synthetic/device/mint/:integrationNode/:vehicleNode", test.AuthInjectorTestHandler(mockUserID), c.GetSyntheticDeviceMintingPayload) + +// s.app = app +// } + +// // TearDownTest after each test truncate tables +// func (s *SyntheticDevicesControllerTestSuite) TearDownTest() { +// test.TruncateTables(s.pdb.DBS().Writer.DB, s.T()) +// } - user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) - s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) +// // TearDownSuite cleanup at end by terminating container +// func (s *SyntheticDevicesControllerTestSuite) TearDownSuite() { +// fmt.Printf("shutting down postgres at with session: %s \n", s.container.SessionID()) - integrations := test.BuildIntegrationForGRPCRequest(10, uint64(1)) - s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), gomock.Any()).Return(integrations, nil) +// if err := s.container.Terminate(s.ctx); err != nil { +// s.T().Fatal(err) +// } +// s.mockCtrl.Finish() +// } - _ = test.BuildDeviceDefinitionGRPC(ksuid.New().String(), "Ford", "Explorer", 2022, nil) +// // Test Runner +// func TestSyntheticDevicesControllerTestSuite(t *testing.T) { +// suite.Run(t, new(SyntheticDevicesControllerTestSuite)) +// } - udID := ksuid.New().String() - _ = test.SetupCreateVehicleNFTForMiddleware(s.T(), *addr, mockUserID, udID, 57, s.pdb) +// func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload() { +// _, addr, err := test.GenerateWallet() +// assert.NoError(s.T(), err) - request := test.BuildRequest("GET", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), "") - response, err := s.app.Test(request) - require.NoError(s.T(), err) +// email := "some@email.com" +// eth := addr.Hex() - body, _ := io.ReadAll(response.Body) +// user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) +// s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) - rawExpectedResp := s.sdc.getEIP712Mint(int64(1), int64(57)) - expectedRespJSON, err := json.Marshal(rawExpectedResp) - assert.NoError(s.T(), err) +// integrations := test.BuildIntegrationForGRPCRequest(10, uint64(1)) +// s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), gomock.Any()).Return(integrations, nil) - assert.Equal(s.T(), fiber.StatusOK, response.StatusCode) - assert.Equal(s.T(), body, expectedRespJSON) -} +// _ = test.BuildDeviceDefinitionGRPC(ksuid.New().String(), "Ford", "Explorer", 2022, nil) -func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload_UserNotFound() { - s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(nil, errors.New("User not found")) +// udID := ksuid.New().String() +// _ = test.SetupCreateVehicleNFTForMiddleware(s.T(), *addr, mockUserID, udID, 57, s.pdb) - request := test.BuildRequest("GET", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), "") - response, err := s.app.Test(request) - require.NoError(s.T(), err) +// request := test.BuildRequest("GET", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), "") +// response, err := s.app.Test(request) +// require.NoError(s.T(), err) - body, _ := io.ReadAll(response.Body) +// body, _ := io.ReadAll(response.Body) - assert.Equal(s.T(), fiber.StatusInternalServerError, response.StatusCode) - assert.Equal(s.T(), []byte(fmt.Sprintf(`{"code":%d,"message":"error occurred when fetching user: User not found"}`, fiber.StatusInternalServerError)), body) -} +// rawExpectedResp := s.sdc.getEIP712Mint(int64(1), int64(57)) +// expectedRespJSON, err := json.Marshal(rawExpectedResp) +// assert.NoError(s.T(), err) -func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload_NoEthereumAddressForUser() { - email := "some@email.com" - user := test.BuildGetUserGRPC(mockUserID, &email, nil, &users.UserReferrer{}) - s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) +// assert.Equal(s.T(), fiber.StatusOK, response.StatusCode) +// assert.Equal(s.T(), body, expectedRespJSON) +// } - request := test.BuildRequest("GET", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), "") - response, err := s.app.Test(request) - require.NoError(s.T(), err) +// func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload_UserNotFound() { +// s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(nil, errors.New("User not found")) - body, _ := io.ReadAll(response.Body) +// request := test.BuildRequest("GET", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), "") +// response, err := s.app.Test(request) +// require.NoError(s.T(), err) - assert.Equal(s.T(), fiber.StatusUnauthorized, response.StatusCode) - assert.Equal(s.T(), []byte(fmt.Sprintf(`{"code":%d,"message":"User does not have an Ethereum address."}`, fiber.StatusUnauthorized)), body) -} +// body, _ := io.ReadAll(response.Body) -func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload_NoIntegrationForID() { - _, addr, err := test.GenerateWallet() - assert.NoError(s.T(), err) +// assert.Equal(s.T(), fiber.StatusInternalServerError, response.StatusCode) +// assert.Equal(s.T(), []byte(fmt.Sprintf(`{"code":%d,"message":"error occurred when fetching user: User not found"}`, fiber.StatusInternalServerError)), body) +// } - eth := addr.Hex() - email := "some@email.com" +// func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload_NoEthereumAddressForUser() { +// email := "some@email.com" +// user := test.BuildGetUserGRPC(mockUserID, &email, nil, &users.UserReferrer{}) +// s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) - user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) - s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) +// request := test.BuildRequest("GET", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), "") +// response, err := s.app.Test(request) +// require.NoError(s.T(), err) - s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), gomock.Any()).Return(nil, errors.New("could not find integration")) +// body, _ := io.ReadAll(response.Body) - udID := ksuid.New().String() - _ = test.SetupCreateVehicleNFTForMiddleware(s.T(), *addr, mockUserID, udID, 57, s.pdb) +// assert.Equal(s.T(), fiber.StatusUnauthorized, response.StatusCode) +// assert.Equal(s.T(), []byte(fmt.Sprintf(`{"code":%d,"message":"User does not have an Ethereum address."}`, fiber.StatusUnauthorized)), body) +// } - request := test.BuildRequest("GET", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), "") - response, err := s.app.Test(request) - require.NoError(s.T(), err) +// func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload_NoIntegrationForID() { +// _, addr, err := test.GenerateWallet() +// assert.NoError(s.T(), err) - body, _ := io.ReadAll(response.Body) +// eth := addr.Hex() +// email := "some@email.com" - assert.Equal(s.T(), fiber.StatusInternalServerError, response.StatusCode) - assert.Equal(s.T(), []byte(fmt.Sprintf(`{"code":%d,"message":"failed to get integration: could not find integration"}`, fiber.StatusInternalServerError)), body) -} +// user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) +// s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) -func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload_VehicleNodeNotExist() { - _, addr, err := test.GenerateWallet() - assert.NoError(s.T(), err) +// s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), gomock.Any()).Return(nil, errors.New("could not find integration")) - eth := addr.Hex() - email := "some@email.com" +// udID := ksuid.New().String() +// _ = test.SetupCreateVehicleNFTForMiddleware(s.T(), *addr, mockUserID, udID, 57, s.pdb) - user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) - s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) +// request := test.BuildRequest("GET", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), "") +// response, err := s.app.Test(request) +// require.NoError(s.T(), err) - request := test.BuildRequest("GET", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), "") - response, err := s.app.Test(request) - require.NoError(s.T(), err) +// body, _ := io.ReadAll(response.Body) - body, _ := io.ReadAll(response.Body) +// assert.Equal(s.T(), fiber.StatusInternalServerError, response.StatusCode) +// assert.Equal(s.T(), []byte(fmt.Sprintf(`{"code":%d,"message":"failed to get integration: could not find integration"}`, fiber.StatusInternalServerError)), body) +// } - assert.Equal(s.T(), fiber.StatusNotFound, response.StatusCode) - assert.Equal(s.T(), []byte(fmt.Sprintf(`{"code":%d,"message":"No vehicle with that id found."}`, fiber.StatusNotFound)), body) -} +// func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload_VehicleNodeNotExist() { +// _, addr, err := test.GenerateWallet() +// assert.NoError(s.T(), err) -func (s *SyntheticDevicesControllerTestSuite) Test_MintSyntheticDeviceSmartcar() { - email := "some@email.com" - eth := userEthAddress - addr := common.HexToAddress(userEthAddress) - deviceEthAddr := common.HexToAddress("11") +// eth := addr.Hex() +// email := "some@email.com" - user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) - s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) +// user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) +// s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) - scInt := &ddgrpc.Integration{ - Id: "22N2xaPOq2WW2gAHBHd0Ikn4Zob", - Vendor: "SmartCar", - TokenId: 1, - } +// request := test.BuildRequest("GET", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), "") +// response, err := s.app.Test(request) +// require.NoError(s.T(), err) - s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), uint64(1)).Return(scInt, nil) +// body, _ := io.ReadAll(response.Body) - _ = test.BuildDeviceDefinitionGRPC(ksuid.New().String(), "Ford", "Explorer", 2022, nil) +// assert.Equal(s.T(), fiber.StatusNotFound, response.StatusCode) +// assert.Equal(s.T(), []byte(fmt.Sprintf(`{"code":%d,"message":"No vehicle with that id found."}`, fiber.StatusNotFound)), body) +// } - udID := ksuid.New().String() - vehicle := test.SetupCreateVehicleNFTForMiddleware(s.T(), addr, mockUserID, udID, 57, s.pdb) +// func (s *SyntheticDevicesControllerTestSuite) Test_MintSyntheticDeviceSmartcar() { +// email := "some@email.com" +// eth := userEthAddress +// addr := common.HexToAddress(userEthAddress) +// deviceEthAddr := common.HexToAddress("11") - vehicleSig := common.HexToAddress("20").Hash().Bytes() - s.syntheticDeviceSigSvc.EXPECT().SignHash(gomock.Any(), gomock.Any(), gomock.Any()).Return(vehicleSig, nil).AnyTimes() - s.syntheticDeviceSigSvc.EXPECT().GetAddress(gomock.Any(), gomock.Any()).Return(deviceEthAddr.Bytes(), nil).AnyTimes() +// user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) +// s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) - s.smartcarClient.EXPECT().ExchangeCode(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockSmartClientToken, nil) - s.smartcarClient.EXPECT().GetExternalID(gomock.Any(), gomock.Any()).Return("smartcarVehicleId", nil) - s.smartcarClient.EXPECT().GetEndpoints(gomock.Any(), gomock.Any(), gomock.Any()).Return([]string{"/odometer", "/location"}, nil) - s.smartcarClient.EXPECT().HasDoorControl(gomock.Any(), mockSmartClientToken.Access, "smartcarVehicleId").Return(true, nil) +// scInt := &ddgrpc.Integration{ +// Id: "22N2xaPOq2WW2gAHBHd0Ikn4Zob", +// Vendor: "SmartCar", +// TokenId: 1, +// } - var kb []byte - mockProducer.ExpectSendMessageWithCheckerFunctionAndSucceed(func(val []byte) error { - kb = val - return nil - }) +// s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), uint64(1)).Return(scInt, nil) - req := fmt.Sprintf(`{ - "credentials": { - "code": "a4d04dad-2b65-4778-94b7-f04996e89907" - }, - "ownerSignature": "%s" - }`, signature) +// _ = test.BuildDeviceDefinitionGRPC(ksuid.New().String(), "Ford", "Explorer", 2022, nil) - request := test.BuildRequest("POST", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), req) - response, err := s.app.Test(request) - require.NoError(s.T(), err) +// udID := ksuid.New().String() +// vehicle := test.SetupCreateVehicleNFTForMiddleware(s.T(), addr, mockUserID, udID, 57, s.pdb) - body, _ := io.ReadAll(response.Body) +// vehicleSig := common.HexToAddress("20").Hash().Bytes() +// s.syntheticDeviceSigSvc.EXPECT().SignHash(gomock.Any(), gomock.Any(), gomock.Any()).Return(vehicleSig, nil).AnyTimes() +// s.syntheticDeviceSigSvc.EXPECT().GetAddress(gomock.Any(), gomock.Any()).Return(deviceEthAddr.Bytes(), nil).AnyTimes() - assert.Equal(s.T(), fiber.StatusOK, response.StatusCode) +// s.smartcarClient.EXPECT().ExchangeCode(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockSmartClientToken, nil) +// s.smartcarClient.EXPECT().GetExternalID(gomock.Any(), gomock.Any()).Return("smartcarVehicleId", nil) +// s.smartcarClient.EXPECT().GetEndpoints(gomock.Any(), gomock.Any(), gomock.Any()).Return([]string{"/odometer", "/location"}, nil) +// s.smartcarClient.EXPECT().HasDoorControl(gomock.Any(), mockSmartClientToken.Access, "smartcarVehicleId").Return(true, nil) - mockProducer.Close() +// var kb []byte +// mockProducer.ExpectSendMessageWithCheckerFunctionAndSucceed(func(val []byte) error { +// kb = val +// return nil +// }) - assert.Equal(s.T(), "{\"message\":\"Submitted synthetic device mint request.\"}", string(body)) +// req := fmt.Sprintf(`{ +// "credentials": { +// "code": "a4d04dad-2b65-4778-94b7-f04996e89907" +// }, +// "ownerSignature": "%s" +// }`, signature) - var me shared.CloudEvent[registry.RequestData] +// request := test.BuildRequest("POST", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), req) +// response, err := s.app.Test(request) +// require.NoError(s.T(), err) - err = json.Unmarshal(kb, &me) - s.Require().NoError(err) +// body, _ := io.ReadAll(response.Body) - abi, err := contracts.RegistryMetaData.GetAbi() - s.Require().NoError(err) +// assert.Equal(s.T(), fiber.StatusOK, response.StatusCode) - method := abi.Methods["mintSyntheticDeviceSign"] +// mockProducer.Close() - callData := me.Data.Data +// assert.Equal(s.T(), "{\"message\":\"Submitted synthetic device mint request.\"}", string(body)) - s.EqualValues(method.ID, callData[:4]) +// var me shared.CloudEvent[registry.RequestData] - o, err := method.Inputs.Unpack(callData[4:]) - s.Require().NoError(err) +// err = json.Unmarshal(kb, &me) +// s.Require().NoError(err) - actualMnInput := o[0].(struct { - IntegrationNode *big.Int `json:"integrationNode"` - VehicleNode *big.Int `json:"vehicleNode"` - SyntheticDeviceSig []uint8 `json:"syntheticDeviceSig"` - VehicleOwnerSig []uint8 `json:"vehicleOwnerSig"` - SyntheticDeviceAddr common.Address `json:"syntheticDeviceAddr"` - AttrInfoPairs []struct { - Attribute string `json:"attribute"` - Info string `json:"info"` - } `json:"attrInfoPairs"` - }) +// abi, err := contracts.RegistryMetaData.GetAbi() +// s.Require().NoError(err) - expectedMnInput := contracts.MintSyntheticDeviceInput{ - IntegrationNode: new(big.Int).SetUint64(1), - VehicleNode: new(big.Int).SetUint64(57), - VehicleOwnerSig: common.FromHex(signature), - SyntheticDeviceAddr: deviceEthAddr, - SyntheticDeviceSig: vehicleSig, - } +// method := abi.Methods["mintSyntheticDeviceSign"] - vnID := types.NewNullDecimal(decimal.New(57, 0)) - syntDevice, err := models.SyntheticDevices( - models.SyntheticDeviceWhere.VehicleTokenID.EQ(vnID), - models.SyntheticDeviceWhere.IntegrationTokenID.EQ(types.NewDecimal(decimal.New(1, 0))), - ).One(s.ctx, s.pdb.DBS().Reader) - assert.NoError(s.T(), err) +// callData := me.Data.Data - assert.Equal(s.T(), syntDevice.IntegrationTokenID, types.NewDecimal(decimal.New(1, 0))) - assert.Equal(s.T(), syntDevice.VehicleTokenID, vnID) +// s.EqualValues(method.ID, callData[:4]) - assert.ObjectsAreEqual(expectedMnInput, actualMnInput) +// o, err := method.Inputs.Unpack(callData[4:]) +// s.Require().NoError(err) - metaTrxReq, err := models.MetaTransactionRequests( - models.MetaTransactionRequestWhere.ID.EQ(syntDevice.MintRequestID), - models.MetaTransactionRequestWhere.Status.EQ(models.MetaTransactionRequestStatusUnsubmitted), - ).Exists(s.ctx, s.pdb.DBS().Reader) - assert.NoError(s.T(), err) +// actualMnInput := o[0].(struct { +// IntegrationNode *big.Int `json:"integrationNode"` +// VehicleNode *big.Int `json:"vehicleNode"` +// SyntheticDeviceSig []uint8 `json:"syntheticDeviceSig"` +// VehicleOwnerSig []uint8 `json:"vehicleOwnerSig"` +// SyntheticDeviceAddr common.Address `json:"syntheticDeviceAddr"` +// AttrInfoPairs []struct { +// Attribute string `json:"attribute"` +// Info string `json:"info"` +// } `json:"attrInfoPairs"` +// }) - assert.Equal(s.T(), metaTrxReq, true) +// expectedMnInput := contracts.MintSyntheticDeviceInput{ +// IntegrationNode: new(big.Int).SetUint64(1), +// VehicleNode: new(big.Int).SetUint64(57), +// VehicleOwnerSig: common.FromHex(signature), +// SyntheticDeviceAddr: deviceEthAddr, +// SyntheticDeviceSig: vehicleSig, +// } - udis, err := models.UserDeviceAPIIntegrations().All(s.ctx, s.pdb.DBS().Reader) - assert.NoError(s.T(), err) +// vnID := types.NewNullDecimal(decimal.New(57, 0)) +// syntDevice, err := models.SyntheticDevices( +// models.SyntheticDeviceWhere.VehicleTokenID.EQ(vnID), +// models.SyntheticDeviceWhere.IntegrationTokenID.EQ(types.NewDecimal(decimal.New(1, 0))), +// ).One(s.ctx, s.pdb.DBS().Reader) +// assert.NoError(s.T(), err) - assert.Equal(s.T(), 1, len(udis)) +// assert.Equal(s.T(), syntDevice.IntegrationTokenID, types.NewDecimal(decimal.New(1, 0))) +// assert.Equal(s.T(), syntDevice.VehicleTokenID, vnID) - decAccessToken, err := s.sdc.cipher.Decrypt(udis[0].AccessToken.String) - assert.NoError(s.T(), err) +// assert.ObjectsAreEqual(expectedMnInput, actualMnInput) - decRefreshToken, err := s.sdc.cipher.Decrypt(udis[0].RefreshToken.String) - assert.NoError(s.T(), err) +// metaTrxReq, err := models.MetaTransactionRequests( +// models.MetaTransactionRequestWhere.ID.EQ(syntDevice.MintRequestID), +// models.MetaTransactionRequestWhere.Status.EQ(models.MetaTransactionRequestStatusUnsubmitted), +// ).Exists(s.ctx, s.pdb.DBS().Reader) +// assert.NoError(s.T(), err) - assert.Equal(s.T(), scInt.Id, udis[0].IntegrationID) - assert.Equal(s.T(), vehicle.UserDeviceID.String, udis[0].UserDeviceID) - assert.Equal(s.T(), mockSmartClientToken.Access, decAccessToken) - assert.Equal(s.T(), mockSmartClientToken.Refresh, decRefreshToken) -} +// assert.Equal(s.T(), metaTrxReq, true) -func (s *SyntheticDevicesControllerTestSuite) TestMintTesla() { - email := "some@email.com" - userEthAddress := "0xFdC646Ad5950ED5cBf2A203C4D8001551b3Ee752" - signature := "0xee3235ef51bd273ec6533db4fe8038add3461bcde83e35d0043d94b4a58d7ba10a9e4648694e45daab12ac5617dffed1a84232e49885dfaf651dbe5e97d349bd1b" - eth := userEthAddress - addr := common.HexToAddress(userEthAddress) - deviceEthAddr := common.HexToAddress("10") - integrationID := 2 - vehicleNode := 56 +// udis, err := models.UserDeviceAPIIntegrations().All(s.ctx, s.pdb.DBS().Reader) +// assert.NoError(s.T(), err) - user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) - s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) +// assert.Equal(s.T(), 1, len(udis)) - integration := test.BuildIntegrationForGRPCRequest(10, uint64(integrationID)) - integration.Vendor = constants.TeslaVendor - integration.TokenId = 2 - s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), gomock.Any()).Return(integration, nil) +// decAccessToken, err := s.sdc.cipher.Decrypt(udis[0].AccessToken.String) +// assert.NoError(s.T(), err) - _ = test.BuildDeviceDefinitionGRPC(ksuid.New().String(), "Tesla", "Model X", 2022, nil) +// decRefreshToken, err := s.sdc.cipher.Decrypt(udis[0].RefreshToken.String) +// assert.NoError(s.T(), err) - udID := ksuid.New().String() - vehicle := test.SetupCreateVehicleNFTForMiddleware(s.T(), addr, mockUserID, udID, int64(vehicleNode), s.pdb) +// assert.Equal(s.T(), scInt.Id, udis[0].IntegrationID) +// assert.Equal(s.T(), vehicle.UserDeviceID.String, udis[0].UserDeviceID) +// assert.Equal(s.T(), mockSmartClientToken.Access, decAccessToken) +// assert.Equal(s.T(), mockSmartClientToken.Refresh, decRefreshToken) +// } - vehicleSig := common.HexToAddress("20").Hash().Bytes() - s.syntheticDeviceSigSvc.EXPECT().SignHash(gomock.Any(), gomock.Any(), gomock.Any()).Return(vehicleSig, nil).AnyTimes() - s.syntheticDeviceSigSvc.EXPECT().GetAddress(gomock.Any(), gomock.Any()).Return(deviceEthAddr.Bytes(), nil).AnyTimes() +// func (s *SyntheticDevicesControllerTestSuite) TestMintTesla() { +// email := "some@email.com" +// userEthAddress := "0xFdC646Ad5950ED5cBf2A203C4D8001551b3Ee752" +// signature := "0xee3235ef51bd273ec6533db4fe8038add3461bcde83e35d0043d94b4a58d7ba10a9e4648694e45daab12ac5617dffed1a84232e49885dfaf651dbe5e97d349bd1b" +// eth := userEthAddress +// addr := common.HexToAddress(userEthAddress) +// deviceEthAddr := common.HexToAddress("10") +// integrationID := 2 +// vehicleNode := 56 - teslaData := services.TeslaVehicle{ID: 13, VehicleID: 666, VIN: "5YJYGDEE9MF073630"} - s.teslaService.EXPECT().GetVehicle(gomock.Any(), gomock.Any()).Return(&teslaData, nil) +// user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) +// s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) - var kb []byte - mockProducer.ExpectSendMessageWithCheckerFunctionAndSucceed(func(val []byte) error { - kb = val - return nil - }) +// integration := test.BuildIntegrationForGRPCRequest(10, uint64(integrationID)) +// integration.Vendor = constants.TeslaVendor +// integration.TokenId = 2 +// s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), gomock.Any()).Return(integration, nil) - teslaClientToken.OwnerSignature = signature - reqB, err := json.Marshal(teslaClientToken) - s.NoError(err) - - request := test.BuildRequest("POST", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", integrationID, vehicleNode), string(reqB)) - response, err := s.app.Test(request) - require.NoError(s.T(), err) - - body, _ := io.ReadAll(response.Body) - - assert.Equal(s.T(), fiber.StatusOK, response.StatusCode) - mockProducer.Close() - - assert.Equal(s.T(), "{\"message\":\"Submitted synthetic device mint request.\"}", string(body)) - - var me shared.CloudEvent[registry.RequestData] +// _ = test.BuildDeviceDefinitionGRPC(ksuid.New().String(), "Tesla", "Model X", 2022, nil) - err = json.Unmarshal(kb, &me) - s.Require().NoError(err) - - abi, err := contracts.RegistryMetaData.GetAbi() - s.Require().NoError(err) +// udID := ksuid.New().String() +// vehicle := test.SetupCreateVehicleNFTForMiddleware(s.T(), addr, mockUserID, udID, int64(vehicleNode), s.pdb) - method := abi.Methods["mintSyntheticDeviceSign"] +// vehicleSig := common.HexToAddress("20").Hash().Bytes() +// s.syntheticDeviceSigSvc.EXPECT().SignHash(gomock.Any(), gomock.Any(), gomock.Any()).Return(vehicleSig, nil).AnyTimes() +// s.syntheticDeviceSigSvc.EXPECT().GetAddress(gomock.Any(), gomock.Any()).Return(deviceEthAddr.Bytes(), nil).AnyTimes() - callData := me.Data.Data +// teslaData := services.TeslaVehicle{ID: 13, VehicleID: 666, VIN: "5YJYGDEE9MF073630"} +// s.teslaService.EXPECT().GetVehicle(gomock.Any(), gomock.Any()).Return(&teslaData, nil) - s.EqualValues(method.ID, callData[:4]) +// var kb []byte +// mockProducer.ExpectSendMessageWithCheckerFunctionAndSucceed(func(val []byte) error { +// kb = val +// return nil +// }) - o, err := method.Inputs.Unpack(callData[4:]) - s.Require().NoError(err) +// teslaClientToken.OwnerSignature = signature +// reqB, err := json.Marshal(teslaClientToken) +// s.NoError(err) + +// request := test.BuildRequest("POST", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", integrationID, vehicleNode), string(reqB)) +// response, err := s.app.Test(request) +// require.NoError(s.T(), err) + +// body, _ := io.ReadAll(response.Body) + +// assert.Equal(s.T(), fiber.StatusOK, response.StatusCode) +// mockProducer.Close() + +// assert.Equal(s.T(), "{\"message\":\"Submitted synthetic device mint request.\"}", string(body)) + +// var me shared.CloudEvent[registry.RequestData] - actualMnInput := o[0].(struct { - IntegrationNode *big.Int `json:"integrationNode"` - VehicleNode *big.Int `json:"vehicleNode"` - SyntheticDeviceSig []uint8 `json:"syntheticDeviceSig"` - VehicleOwnerSig []uint8 `json:"vehicleOwnerSig"` - SyntheticDeviceAddr common.Address `json:"syntheticDeviceAddr"` - AttrInfoPairs []struct { - Attribute string `json:"attribute"` - Info string `json:"info"` - } `json:"attrInfoPairs"` - }) +// err = json.Unmarshal(kb, &me) +// s.Require().NoError(err) + +// abi, err := contracts.RegistryMetaData.GetAbi() +// s.Require().NoError(err) - expectedMnInput := contracts.MintSyntheticDeviceInput{ - IntegrationNode: new(big.Int).SetUint64(uint64(integrationID)), - VehicleNode: new(big.Int).SetUint64(uint64(vehicleNode)), - VehicleOwnerSig: common.FromHex(signature), - SyntheticDeviceAddr: deviceEthAddr, - SyntheticDeviceSig: vehicleSig, - } +// method := abi.Methods["mintSyntheticDeviceSign"] - vnID := types.NewNullDecimal(decimal.New(int64(vehicleNode), 0)) - syntDevice, err := models.SyntheticDevices( - models.SyntheticDeviceWhere.VehicleTokenID.EQ(vnID), - models.SyntheticDeviceWhere.IntegrationTokenID.EQ(types.NewDecimal(decimal.New(int64(integrationID), 0))), - ).One(s.ctx, s.pdb.DBS().Reader) - assert.NoError(s.T(), err) +// callData := me.Data.Data - assert.Equal(s.T(), syntDevice.IntegrationTokenID, types.NewDecimal(decimal.New(int64(integrationID), 0))) - assert.Equal(s.T(), syntDevice.VehicleTokenID, vnID) +// s.EqualValues(method.ID, callData[:4]) - assert.ObjectsAreEqual(expectedMnInput, actualMnInput) +// o, err := method.Inputs.Unpack(callData[4:]) +// s.Require().NoError(err) - metaTrxReq, err := models.MetaTransactionRequests( - models.MetaTransactionRequestWhere.ID.EQ(syntDevice.MintRequestID), - models.MetaTransactionRequestWhere.Status.EQ(models.MetaTransactionRequestStatusUnsubmitted), - ).Exists(s.ctx, s.pdb.DBS().Reader) - assert.NoError(s.T(), err) +// actualMnInput := o[0].(struct { +// IntegrationNode *big.Int `json:"integrationNode"` +// VehicleNode *big.Int `json:"vehicleNode"` +// SyntheticDeviceSig []uint8 `json:"syntheticDeviceSig"` +// VehicleOwnerSig []uint8 `json:"vehicleOwnerSig"` +// SyntheticDeviceAddr common.Address `json:"syntheticDeviceAddr"` +// AttrInfoPairs []struct { +// Attribute string `json:"attribute"` +// Info string `json:"info"` +// } `json:"attrInfoPairs"` +// }) - assert.Equal(s.T(), metaTrxReq, true) +// expectedMnInput := contracts.MintSyntheticDeviceInput{ +// IntegrationNode: new(big.Int).SetUint64(uint64(integrationID)), +// VehicleNode: new(big.Int).SetUint64(uint64(vehicleNode)), +// VehicleOwnerSig: common.FromHex(signature), +// SyntheticDeviceAddr: deviceEthAddr, +// SyntheticDeviceSig: vehicleSig, +// } - udi, err := models.UserDeviceAPIIntegrations(models.UserDeviceAPIIntegrationWhere.UserDeviceID.EQ(udID)).One(s.ctx, s.pdb.DBS().Reader) - assert.NoError(s.T(), err) +// vnID := types.NewNullDecimal(decimal.New(int64(vehicleNode), 0)) +// syntDevice, err := models.SyntheticDevices( +// models.SyntheticDeviceWhere.VehicleTokenID.EQ(vnID), +// models.SyntheticDeviceWhere.IntegrationTokenID.EQ(types.NewDecimal(decimal.New(int64(integrationID), 0))), +// ).One(s.ctx, s.pdb.DBS().Reader) +// assert.NoError(s.T(), err) - decryptedAccessTkn, err := s.sdc.cipher.Decrypt(udi.AccessToken.String) - assert.NoError(s.T(), err) +// assert.Equal(s.T(), syntDevice.IntegrationTokenID, types.NewDecimal(decimal.New(int64(integrationID), 0))) +// assert.Equal(s.T(), syntDevice.VehicleTokenID, vnID) - decryptedRefreshTkn, err := s.sdc.cipher.Decrypt(udi.RefreshToken.String) - assert.NoError(s.T(), err) +// assert.ObjectsAreEqual(expectedMnInput, actualMnInput) - assert.Equal(s.T(), integration.Id, udi.IntegrationID) - assert.Equal(s.T(), vehicle.UserDeviceID.String, udi.UserDeviceID) - assert.Equal(s.T(), teslaClientToken.Credentials.AccessToken, decryptedAccessTkn) - assert.Equal(s.T(), teslaClientToken.Credentials.RefreshToken, decryptedRefreshTkn) -} +// metaTrxReq, err := models.MetaTransactionRequests( +// models.MetaTransactionRequestWhere.ID.EQ(syntDevice.MintRequestID), +// models.MetaTransactionRequestWhere.Status.EQ(models.MetaTransactionRequestStatusUnsubmitted), +// ).Exists(s.ctx, s.pdb.DBS().Reader) +// assert.NoError(s.T(), err) -func (s *SyntheticDevicesControllerTestSuite) TestSignSyntheticDeviceMintingPayload_BadSignatureFailure() { - email := "some@email.com" - eth := userEthAddress +// assert.Equal(s.T(), metaTrxReq, true) - user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) - s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) +// udi, err := models.UserDeviceAPIIntegrations(models.UserDeviceAPIIntegrationWhere.UserDeviceID.EQ(udID)).One(s.ctx, s.pdb.DBS().Reader) +// assert.NoError(s.T(), err) - scInt := &ddgrpc.Integration{ - Id: "22N2xaPOq2WW2gAHBHd0Ikn4Zob", - Vendor: "SmartCar", - TokenId: 1, - } +// decryptedAccessTkn, err := s.sdc.cipher.Decrypt(udi.AccessToken.String) +// assert.NoError(s.T(), err) - s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), uint64(1)).Return(scInt, nil) +// decryptedRefreshTkn, err := s.sdc.cipher.Decrypt(udi.RefreshToken.String) +// assert.NoError(s.T(), err) - udID := ksuid.New().String() - _ = test.SetupCreateVehicleNFTForMiddleware(s.T(), common.HexToAddress(userEthAddress), mockUserID, udID, 57, s.pdb) +// assert.Equal(s.T(), integration.Id, udi.IntegrationID) +// assert.Equal(s.T(), vehicle.UserDeviceID.String, udi.UserDeviceID) +// assert.Equal(s.T(), teslaClientToken.Credentials.AccessToken, decryptedAccessTkn) +// assert.Equal(s.T(), teslaClientToken.Credentials.RefreshToken, decryptedRefreshTkn) +// } - req := fmt.Sprintf(`{ - "credentials": { - "code": "a4d04dad-2b65-4778-94b7-f04996e89907" - }, - "ownerSignature": "%s" - }`, "0xa3438e5cb667dc63ebd694167ae3ad83585f2834c9b04895dd890f805c4c459a024ed9df1b03872536b4ac0c7720d02cb787884a093cfcde5c3bd7f94657e30c1b") - request := test.BuildRequest("POST", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), req) - response, err := s.app.Test(request) - require.NoError(s.T(), err) +// func (s *SyntheticDevicesControllerTestSuite) TestSignSyntheticDeviceMintingPayload_BadSignatureFailure() { +// email := "some@email.com" +// eth := userEthAddress - body, _ := io.ReadAll(response.Body) +// user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) +// s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) - msg := struct { - Message string `json:"message"` - }{} - err = json.Unmarshal(body, &msg) - s.NoError(err) +// scInt := &ddgrpc.Integration{ +// Id: "22N2xaPOq2WW2gAHBHd0Ikn4Zob", +// Vendor: "SmartCar", +// TokenId: 1, +// } - assert.Equal(s.T(), fiber.StatusInternalServerError, response.StatusCode) - assert.Equal(s.T(), secp256k1.ErrRecoverFailed.Error(), msg.Message) -} - -func (s *SyntheticDevicesControllerTestSuite) Test_Synthetic_Device_Sequence() { - s.pdb, s.container = test.StartContainerDatabase(s.ctx, s.T(), migrationsDirRelPath) // resets sequence in pg, if removed, must account for Tesla and Smartcar mints above - - syntDeviceCount, err := models.SyntheticDevices().Count(s.ctx, s.pdb.DBS().Reader) // expect that count will be 0 - assert.NoError(s.T(), err) - - childKeyNumber, err := s.sdc.generateNextChildKeyNumber(s.ctx) - assert.NoError(s.T(), err) - - assert.Equal(s.T(), int(syntDeviceCount)+1, childKeyNumber) - - childKeyNumber, err = s.sdc.generateNextChildKeyNumber(s.ctx) - assert.NoError(s.T(), err) +// s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), uint64(1)).Return(scInt, nil) - assert.Equal(s.T(), int(syntDeviceCount)+2, childKeyNumber) -} +// udID := ksuid.New().String() +// _ = test.SetupCreateVehicleNFTForMiddleware(s.T(), common.HexToAddress(userEthAddress), mockUserID, udID, 57, s.pdb) + +// req := fmt.Sprintf(`{ +// "credentials": { +// "code": "a4d04dad-2b65-4778-94b7-f04996e89907" +// }, +// "ownerSignature": "%s" +// }`, "0xa3438e5cb667dc63ebd694167ae3ad83585f2834c9b04895dd890f805c4c459a024ed9df1b03872536b4ac0c7720d02cb787884a093cfcde5c3bd7f94657e30c1b") +// request := test.BuildRequest("POST", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), req) +// response, err := s.app.Test(request) +// require.NoError(s.T(), err) + +// body, _ := io.ReadAll(response.Body) + +// msg := struct { +// Message string `json:"message"` +// }{} +// err = json.Unmarshal(body, &msg) +// s.NoError(err) + +// assert.Equal(s.T(), fiber.StatusInternalServerError, response.StatusCode) +// assert.Equal(s.T(), secp256k1.ErrRecoverFailed.Error(), msg.Message) +// } + +// func (s *SyntheticDevicesControllerTestSuite) Test_Synthetic_Device_Sequence() { +// s.pdb, s.container = test.StartContainerDatabase(s.ctx, s.T(), migrationsDirRelPath) // resets sequence in pg, if removed, must account for Tesla and Smartcar mints above + +// syntDeviceCount, err := models.SyntheticDevices().Count(s.ctx, s.pdb.DBS().Reader) // expect that count will be 0 +// assert.NoError(s.T(), err) + +// childKeyNumber, err := s.sdc.generateNextChildKeyNumber(s.ctx) +// assert.NoError(s.T(), err) + +// assert.Equal(s.T(), int(syntDeviceCount)+1, childKeyNumber) + +// childKeyNumber, err = s.sdc.generateNextChildKeyNumber(s.ctx) +// assert.NoError(s.T(), err) + +// assert.Equal(s.T(), int(syntDeviceCount)+2, childKeyNumber) +// } diff --git a/internal/controllers/user_devices_controller.go b/internal/controllers/user_devices_controller.go index e46f51f39..955b947b8 100644 --- a/internal/controllers/user_devices_controller.go +++ b/internal/controllers/user_devices_controller.go @@ -15,6 +15,7 @@ import ( "strings" "time" + "github.com/ericlagergren/decimal" smartcar "github.com/smartcar/go-sdk" "github.com/DIMO-Network/shared/redis" @@ -42,6 +43,7 @@ import ( "github.com/tidwall/gjson" "github.com/volatiletech/null/v8" "github.com/volatiletech/sqlboiler/v4/boil" + "github.com/volatiletech/sqlboiler/v4/queries" "github.com/volatiletech/sqlboiler/v4/queries/qm" "github.com/volatiletech/sqlboiler/v4/types" @@ -79,6 +81,7 @@ type UserDevicesController struct { usersClient pb.UserServiceClient deviceDataSvc services.DeviceDataService NATSSvc *services.NATSService + wallet services.SyntheticWalletInstanceService } // PrivilegedDevices contains all devices for which a privilege has been shared @@ -133,6 +136,7 @@ func NewUserDevicesController(settings *config.Settings, usersClient pb.UserServiceClient, deviceDataSvc services.DeviceDataService, natsSvc *services.NATSService, + wallet services.SyntheticWalletInstanceService, ) UserDevicesController { return UserDevicesController{ Settings: settings, @@ -159,6 +163,7 @@ func NewUserDevicesController(settings *config.Settings, usersClient: usersClient, deviceDataSvc: deviceDataSvc, NATSSvc: natsSvc, + wallet: wallet, } } @@ -326,6 +331,7 @@ func (udc *UserDevicesController) GetUserDevices(c *fiber.Ctx) error { query = append(query, qm.Load(models.UserDeviceRels.UserDeviceAPIIntegrations), qm.Load(qm.Rels(models.UserDeviceRels.VehicleNFT, models.VehicleNFTRels.MintRequest)), + qm.Load(qm.Rels(models.UserDeviceRels.VehicleNFT, models.VehicleNFTRels.VehicleTokenSyntheticDevices, models.SyntheticDeviceRels.MintRequest)), qm.OrderBy(models.UserDeviceColumns.CreatedAt+" DESC")) devices, err := models.UserDevices(query...).All(c.Context(), udc.DBS().Reader) @@ -1726,6 +1732,7 @@ func (udc *UserDevicesController) PostMintDevice(c *fiber.Ctx) error { userDevice, err := models.UserDevices( models.UserDeviceWhere.ID.EQ(userDeviceID), qm.Load(qm.Rels(models.UserDeviceRels.VehicleNFT, models.VehicleNFTRels.MintRequest)), + qm.Load(qm.Rels(models.UserDeviceRels.UserDeviceAPIIntegrations)), ).One(c.Context(), udc.DBS().Reader.DB) if err != nil { if err == sql.ErrNoRows { @@ -1883,6 +1890,81 @@ func (udc *UserDevicesController) PostMintDevice(c *fiber.Ctx) error { return err } + if udais := userDevice.R.UserDeviceAPIIntegrations; !udc.Settings.IsProduction() && len(udais) != 0 { + intID := uint64(0) + for _, udai := range udais { + in, err := udc.DeviceDefSvc.GetIntegrationByID(c.Context(), udai.IntegrationID) + if err != nil { + return err + } + + if in.Vendor == constants.TeslaVendor { + intID = in.TokenId + break + } else if in.Vendor == constants.SmartCarVendor { + intID = in.TokenId + } + } + + if intID != 0 { + var seq struct { + NextVal int `boil:"nextval"` + } + + qry := fmt.Sprintf("SELECT nextval('%s.synthetic_devices_serial_sequence');", udc.Settings.DB.Name) + err := queries.Raw(qry).Bind(c.Context(), udc.DBS().Writer, &seq) + if err != nil { + return err + } + + childNum := seq.NextVal + + var wallet services.SyntheticWalletInstanceService + + addr, err := wallet.GetAddress(c.Context(), uint32(childNum)) + if err != nil { + return err + } + + mvss := registry.MintVehicleAndSdSign{ + IntegrationNode: new(big.Int).SetUint64(intID), + } + + hash, err := client.Hash(&mvss) + if err != nil { + return err + } + + sign, err := wallet.SignHash(c.Context(), uint32(childNum), hash.Bytes()) + if err != nil { + return err + } + + sd := models.SyntheticDevice{ + IntegrationTokenID: types.NewDecimal(decimal.New(int64(intID), 0)), + MintRequestID: requestID, + WalletChildNumber: seq.NextVal, + WalletAddress: addr, + } + + sd.Insert(c.Context(), udc.DBS().Writer, boil.Infer()) + + return client.MintVehicleAndSDign(requestID, contracts.MintVehicleAndSdInput{ + ManufacturerNode: makeTokenID, + Owner: realAddr, + AttrInfoPairsVehicle: []contracts.AttributeInfoPair{ + {Attribute: "Make", Info: deviceMake}, + {Attribute: "Model", Info: deviceModel}, + {Attribute: "Year", Info: deviceYear}, + }, + IntegrationNode: new(big.Int).SetUint64(intID), + VehicleOwnerSig: sigBytes, + SyntheticDeviceSig: sign, + AttrInfoPairsDevice: []contracts.AttributeInfoPair{}, + }) + } + } + logger.Info().Msgf("Submitted metatransaction request %s", requestID) return client.MintVehicleSign(requestID, makeTokenID, realAddr, []contracts.AttributeInfoPair{ diff --git a/internal/controllers/user_devices_controller_test.go b/internal/controllers/user_devices_controller_test.go index 5c3bec864..fc2850f97 100644 --- a/internal/controllers/user_devices_controller_test.go +++ b/internal/controllers/user_devices_controller_test.go @@ -107,7 +107,7 @@ func (s *UserDevicesControllerTestSuite) SetupSuite() { s.testUserID = "123123" testUserID2 := "3232451" c := NewUserDevicesController(&config.Settings{Port: "3000", Environment: "prod"}, s.pdb.DBS, logger, s.deviceDefSvc, s.deviceDefIntSvc, &fakeEventService{}, s.scClient, s.scTaskSvc, teslaSvc, teslaTaskService, new(shared.ROT13Cipher), s.autoPiSvc, - s.nhtsaService, autoPiIngest, deviceDefinitionIngest, autoPiTaskSvc, nil, nil, nil, s.redisClient, nil, s.usersClient, nil, s.natsService) + s.nhtsaService, autoPiIngest, deviceDefinitionIngest, autoPiTaskSvc, nil, nil, nil, s.redisClient, nil, s.usersClient, nil, s.natsService, nil) app := test.SetupAppFiber(*logger) app.Post("/user/devices", test.AuthInjectorTestHandler(s.testUserID), c.RegisterDeviceForUser) app.Post("/user/devices/fromvin", test.AuthInjectorTestHandler(s.testUserID), c.RegisterDeviceForUserFromVIN) diff --git a/internal/controllers/user_integrations_controller_test.go b/internal/controllers/user_integrations_controller_test.go index f601813d9..caa7a779e 100644 --- a/internal/controllers/user_integrations_controller_test.go +++ b/internal/controllers/user_integrations_controller_test.go @@ -107,7 +107,7 @@ func (s *UserIntegrationsControllerTestSuite) SetupSuite() { logger := test.Logger() c := NewUserDevicesController(&config.Settings{Port: "3000"}, s.pdb.DBS, logger, s.deviceDefSvc, s.deviceDefIntSvc, s.eventSvc, s.scClient, s.scTaskSvc, s.teslaSvc, s.teslaTaskService, new(shared.ROT13Cipher), s.autopiAPISvc, nil, - s.autoPiIngest, s.deviceDefinitionRegistrar, s.autoPiTaskService, nil, nil, nil, s.redisClient, nil, nil, nil, s.natsSvc) + s.autoPiIngest, s.deviceDefinitionRegistrar, s.autoPiTaskService, nil, nil, nil, s.redisClient, nil, nil, nil, s.natsSvc, nil) app := test.SetupAppFiber(*logger) @@ -291,7 +291,7 @@ func (s *UserIntegrationsControllerTestSuite) TestPostSmartCar_FailureTestVIN() logger := test.Logger() c := NewUserDevicesController(&config.Settings{Port: "3000", Environment: "prod"}, s.pdb.DBS, logger, s.deviceDefSvc, s.deviceDefIntSvc, s.eventSvc, s.scClient, s.scTaskSvc, s.teslaSvc, s.teslaTaskService, new(shared.ROT13Cipher), s.autopiAPISvc, nil, - s.autoPiIngest, s.deviceDefinitionRegistrar, s.autoPiTaskService, nil, nil, nil, s.redisClient, nil, nil, nil, s.natsSvc) + s.autoPiIngest, s.deviceDefinitionRegistrar, s.autoPiTaskService, nil, nil, nil, s.redisClient, nil, nil, nil, s.natsSvc, nil) app := test.SetupAppFiber(*logger) @@ -516,7 +516,7 @@ func (s *UserIntegrationsControllerTestSuite) TestPostAutoPiBlockedForDuplicateD // specific dependency and controller autopiAPISvc := mock_services.NewMockAutoPiAPIService(s.mockCtrl) logger := test.Logger() - c := NewUserDevicesController(&config.Settings{Port: "3000"}, s.pdb.DBS, logger, s.deviceDefSvc, s.deviceDefIntSvc, &fakeEventService{}, s.scClient, s.scTaskSvc, s.teslaSvc, s.teslaTaskService, new(shared.ROT13Cipher), autopiAPISvc, nil, s.autoPiIngest, s.deviceDefinitionRegistrar, s.autoPiTaskService, nil, nil, nil, nil, nil, nil, nil, nil) + c := NewUserDevicesController(&config.Settings{Port: "3000"}, s.pdb.DBS, logger, s.deviceDefSvc, s.deviceDefIntSvc, &fakeEventService{}, s.scClient, s.scTaskSvc, s.teslaSvc, s.teslaTaskService, new(shared.ROT13Cipher), autopiAPISvc, nil, s.autoPiIngest, s.deviceDefinitionRegistrar, s.autoPiTaskService, nil, nil, nil, nil, nil, nil, nil, nil, nil) app := test.SetupAppFiber(*logger) app.Post("/user/devices/:userDeviceID/integrations/:integrationID", test.AuthInjectorTestHandler(testUserID), c.RegisterDeviceIntegration) // arrange @@ -552,7 +552,7 @@ func (s *UserIntegrationsControllerTestSuite) TestPostAutoPiBlockedForDuplicateD // specific dependency and controller autopiAPISvc := mock_services.NewMockAutoPiAPIService(s.mockCtrl) logger := test.Logger() - c := NewUserDevicesController(&config.Settings{Port: "3000"}, s.pdb.DBS, logger, s.deviceDefSvc, s.deviceDefIntSvc, &fakeEventService{}, s.scClient, s.scTaskSvc, s.teslaSvc, s.teslaTaskService, new(shared.ROT13Cipher), autopiAPISvc, nil, s.autoPiIngest, s.deviceDefinitionRegistrar, s.autoPiTaskService, nil, nil, nil, nil, nil, nil, nil, nil) + c := NewUserDevicesController(&config.Settings{Port: "3000"}, s.pdb.DBS, logger, s.deviceDefSvc, s.deviceDefIntSvc, &fakeEventService{}, s.scClient, s.scTaskSvc, s.teslaSvc, s.teslaTaskService, new(shared.ROT13Cipher), autopiAPISvc, nil, s.autoPiIngest, s.deviceDefinitionRegistrar, s.autoPiTaskService, nil, nil, nil, nil, nil, nil, nil, nil, nil) app := test.SetupAppFiber(*logger) app.Post("/user/devices/:userDeviceID/integrations/:integrationID", test.AuthInjectorTestHandler(testUser2), c.RegisterDeviceIntegration) // arrange @@ -588,7 +588,7 @@ func (s *UserIntegrationsControllerTestSuite) TestGetAutoPiInfoNoUDAI_ShouldUpda const environment = "prod" // shouldUpdate only applies in prod // specific dependency and controller autopiAPISvc := mock_services.NewMockAutoPiAPIService(s.mockCtrl) - c := NewUserDevicesController(&config.Settings{Port: "3000", Environment: environment}, s.pdb.DBS, test.Logger(), s.deviceDefSvc, s.deviceDefIntSvc, &fakeEventService{}, s.scClient, s.scTaskSvc, s.teslaSvc, s.teslaTaskService, new(shared.ROT13Cipher), autopiAPISvc, nil, s.autoPiIngest, s.deviceDefinitionRegistrar, nil, nil, nil, nil, nil, nil, nil, nil, nil) + c := NewUserDevicesController(&config.Settings{Port: "3000", Environment: environment}, s.pdb.DBS, test.Logger(), s.deviceDefSvc, s.deviceDefIntSvc, &fakeEventService{}, s.scClient, s.scTaskSvc, s.teslaSvc, s.teslaTaskService, new(shared.ROT13Cipher), autopiAPISvc, nil, s.autoPiIngest, s.deviceDefinitionRegistrar, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) app := fiber.New() logger := zerolog.Nop() app.Get("/aftermarket/device/by-serial/:serial", test.AuthInjectorTestHandler(testUserID), owner.AftermarketDevice(s.pdb, s.userClient, &logger), c.GetAutoPiUnitInfo) @@ -626,7 +626,7 @@ func (s *UserIntegrationsControllerTestSuite) TestGetAutoPiInfoNoUDAI_UpToDate() const environment = "prod" // shouldUpdate only applies in prod // specific dependency and controller autopiAPISvc := mock_services.NewMockAutoPiAPIService(s.mockCtrl) - c := NewUserDevicesController(&config.Settings{Port: "3000", Environment: environment}, s.pdb.DBS, test.Logger(), s.deviceDefSvc, s.deviceDefIntSvc, &fakeEventService{}, s.scClient, s.scTaskSvc, s.teslaSvc, s.teslaTaskService, new(shared.ROT13Cipher), autopiAPISvc, nil, s.autoPiIngest, s.deviceDefinitionRegistrar, nil, nil, nil, nil, nil, nil, nil, nil, nil) + c := NewUserDevicesController(&config.Settings{Port: "3000", Environment: environment}, s.pdb.DBS, test.Logger(), s.deviceDefSvc, s.deviceDefIntSvc, &fakeEventService{}, s.scClient, s.scTaskSvc, s.teslaSvc, s.teslaTaskService, new(shared.ROT13Cipher), autopiAPISvc, nil, s.autoPiIngest, s.deviceDefinitionRegistrar, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) app := fiber.New() logger := zerolog.Nop() app.Get("/aftermarket/device/by-serial/:serial", test.AuthInjectorTestHandler(testUserID), owner.AftermarketDevice(s.pdb, s.userClient, &logger), c.GetAutoPiUnitInfo) @@ -661,7 +661,7 @@ func (s *UserIntegrationsControllerTestSuite) TestGetAutoPiInfoNoUDAI_FutureUpda const environment = "prod" // shouldUpdate only applies in prod // specific dependency and controller autopiAPISvc := mock_services.NewMockAutoPiAPIService(s.mockCtrl) - c := NewUserDevicesController(&config.Settings{Port: "3000", Environment: environment}, s.pdb.DBS, test.Logger(), s.deviceDefSvc, s.deviceDefIntSvc, &fakeEventService{}, s.scClient, s.scTaskSvc, s.teslaSvc, s.teslaTaskService, new(shared.ROT13Cipher), autopiAPISvc, nil, s.autoPiIngest, s.deviceDefinitionRegistrar, nil, nil, nil, nil, nil, nil, nil, nil, nil) + c := NewUserDevicesController(&config.Settings{Port: "3000", Environment: environment}, s.pdb.DBS, test.Logger(), s.deviceDefSvc, s.deviceDefIntSvc, &fakeEventService{}, s.scClient, s.scTaskSvc, s.teslaSvc, s.teslaTaskService, new(shared.ROT13Cipher), autopiAPISvc, nil, s.autoPiIngest, s.deviceDefinitionRegistrar, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) app := fiber.New() logger := zerolog.Nop() app.Get("/aftermarket/device/by-serial/:serial", test.AuthInjectorTestHandler(testUserID), owner.AftermarketDevice(s.pdb, s.userClient, &logger), c.GetAutoPiUnitInfo) @@ -698,7 +698,7 @@ func (s *UserIntegrationsControllerTestSuite) TestGetAutoPiInfoNoUDAI_ShouldUpda const environment = "prod" // shouldUpdate only applies in prod // specific dependency and controller autopiAPISvc := mock_services.NewMockAutoPiAPIService(s.mockCtrl) - c := NewUserDevicesController(&config.Settings{Port: "3000", Environment: environment}, s.pdb.DBS, test.Logger(), s.deviceDefSvc, s.deviceDefIntSvc, &fakeEventService{}, s.scClient, s.scTaskSvc, s.teslaSvc, s.teslaTaskService, new(shared.ROT13Cipher), autopiAPISvc, nil, s.autoPiIngest, s.deviceDefinitionRegistrar, nil, nil, nil, nil, nil, nil, nil, nil, nil) + c := NewUserDevicesController(&config.Settings{Port: "3000", Environment: environment}, s.pdb.DBS, test.Logger(), s.deviceDefSvc, s.deviceDefIntSvc, &fakeEventService{}, s.scClient, s.scTaskSvc, s.teslaSvc, s.teslaTaskService, new(shared.ROT13Cipher), autopiAPISvc, nil, s.autoPiIngest, s.deviceDefinitionRegistrar, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) app := fiber.New() logger := zerolog.Nop() app.Get("/aftermarket/device/by-serial/:serial", test.AuthInjectorTestHandler(testUserID), owner.AftermarketDevice(s.pdb, s.userClient, &logger), c.GetAutoPiUnitInfo) @@ -746,7 +746,7 @@ func (s *UserIntegrationsControllerTestSuite) TestPairAftermarketNoLegacy() { userAddr := crypto.PubkeyToAddress(privateKey.PublicKey) autopiAPISvc := mock_services.NewMockAutoPiAPIService(s.mockCtrl) - c := NewUserDevicesController(&config.Settings{Port: "3000", DIMORegistryChainID: 1337, DIMORegistryAddr: common.BigToAddress(big.NewInt(7)).Hex()}, s.pdb.DBS, test.Logger(), s.deviceDefSvc, s.deviceDefIntSvc, &fakeEventService{}, s.scClient, s.scTaskSvc, s.teslaSvc, s.teslaTaskService, new(shared.ROT13Cipher), autopiAPISvc, nil, s.autoPiIngest, s.deviceDefinitionRegistrar, nil, kprod, nil, nil, nil, nil, s.userClient, nil, nil) + c := NewUserDevicesController(&config.Settings{Port: "3000", DIMORegistryChainID: 1337, DIMORegistryAddr: common.BigToAddress(big.NewInt(7)).Hex()}, s.pdb.DBS, test.Logger(), s.deviceDefSvc, s.deviceDefIntSvc, &fakeEventService{}, s.scClient, s.scTaskSvc, s.teslaSvc, s.teslaTaskService, new(shared.ROT13Cipher), autopiAPISvc, nil, s.autoPiIngest, s.deviceDefinitionRegistrar, nil, kprod, nil, nil, nil, nil, s.userClient, nil, nil, nil) s.deviceDefIntSvc.EXPECT().GetAutoPiIntegration(gomock.Any()).Return(&ddgrpc.Integration{Id: ksuid.New().String()}, nil).AnyTimes() userID := "louxUser" diff --git a/internal/services/registry/client.go b/internal/services/registry/client.go index c84a5fb25..7bcf04088 100644 --- a/internal/services/registry/client.go +++ b/internal/services/registry/client.go @@ -149,6 +149,28 @@ func (m *UnPairAftermarketDeviceSign) Message() signer.TypedDataMessage { } } +// MintVehicleAndSdSign(uint256 integrationNode) +// Only signed by the synthetic device's wallet. +type MintVehicleAndSdSign struct { + IntegrationNode *big.Int +} + +func (m *MintVehicleAndSdSign) Name() string { + return "MintVehicleAndSdSign" +} + +func (m *MintVehicleAndSdSign) Type() []signer.Type { + return []signer.Type{ + {Name: "integrationNode", Type: "uint256"}, + } +} + +func (m *MintVehicleAndSdSign) Message() signer.TypedDataMessage { + return signer.TypedDataMessage{ + "integrationNode": hexutil.EncodeBig(m.IntegrationNode), + } +} + type Message interface { Name() string Type() []signer.Type @@ -282,12 +304,12 @@ func (c *Client) MintVehicleAndSDign(requestID string, data contracts.MintVehicl return err } - data_, err := abi.Pack("mintVehicleAndSdSign", data) + callData, err := abi.Pack("mintVehicleAndSdSign", data) if err != nil { return err } - return c.sendRequest(requestID, data_) + return c.sendRequest(requestID, callData) } func (c *Client) sendRequest(requestID string, data []byte) error { diff --git a/internal/services/registry/storage.go b/internal/services/registry/storage.go index c90f48a7e..5ffa21bbe 100644 --- a/internal/services/registry/storage.go +++ b/internal/services/registry/storage.go @@ -101,6 +101,27 @@ func (p *proc) Handle(ctx context.Context, data *ceData) error { } logger.Info().Str("userDeviceId", mtr.R.MintRequestVehicleNFT.UserDeviceID.String).Msg("Vehicle minted.") + } else if l1.Topics[0] == syntheticDeviceMintedEvent.ID { + // We must be doing a combined vehicle and SD mint. This always comes second. + var out contracts.RegistrySyntheticDeviceNodeMinted + + sd := mtr.R.MintRequestSyntheticDevice + if sd == nil { + logger.Err(err).Msg("Impossible") + return nil + } + + err := p.parseLog(out, syntheticDeviceMintedEvent, l1) + if err != nil { + return err + } + + sd.VehicleTokenID = mtr.R.MintRequestVehicleNFT.TokenID + sd.TokenID = types.NewNullDecimal(new(decimal.Big).SetBigMantScale(out.SyntheticDeviceNode, 0)) + _, err = sd.Update(ctx, p.DB().Writer, boil.Infer()) + if err != nil { + return err + } } } case mtr.R.ClaimMetaTransactionRequestAftermarketDevice != nil: From 4adb553c0ed674617d9cf5fb0739414d0ecb5054 Mon Sep 17 00:00:00 2001 From: Dylan Moreland Date: Mon, 24 Jul 2023 20:18:41 -0400 Subject: [PATCH 05/11] Use shared wallet, make some safer settings --- cmd/devices-api/dependency_injection.go | 2 +- go.mod | 32 +++---- go.sum | 96 +++++++++++++++++++ .../controllers/user_devices_controller.go | 6 +- settings.sample.yaml | 5 + 5 files changed, 120 insertions(+), 21 deletions(-) diff --git a/cmd/devices-api/dependency_injection.go b/cmd/devices-api/dependency_injection.go index 9b1a7ddc2..f6567e48b 100644 --- a/cmd/devices-api/dependency_injection.go +++ b/cmd/devices-api/dependency_injection.go @@ -84,7 +84,7 @@ func (dc *dependencyContainer) getS3NFTServiceClient(ctx context.Context) *s3.Cl if dc.s3NFTServiceClient == nil { cfg, err := awsconfig.LoadDefaultConfig(ctx, - awsconfig.WithRegion(dc.settings.AWSRegion), + // awsconfig.WithRegion(dc.settings.AWSRegion), // Comment the below out if not using localhost awsconfig.WithEndpointResolverWithOptions(aws.EndpointResolverWithOptionsFunc( func(service, region string, options ...any) (aws.Endpoint, error) { diff --git a/go.mod b/go.mod index e41983978..d87f87e67 100644 --- a/go.mod +++ b/go.mod @@ -12,10 +12,10 @@ require ( github.com/Shopify/sarama v1.38.1 github.com/ThreeDotsLabs/watermill v1.1.1 github.com/ThreeDotsLabs/watermill-kafka/v2 v2.2.1 - github.com/aws/aws-sdk-go-v2 v1.17.8 - github.com/aws/aws-sdk-go-v2/config v1.18.21 - github.com/aws/aws-sdk-go-v2/service/kms v1.20.7 - github.com/aws/aws-sdk-go-v2/service/s3 v1.31.3 + github.com/aws/aws-sdk-go-v2 v1.19.0 + github.com/aws/aws-sdk-go-v2/config v1.18.28 + github.com/aws/aws-sdk-go-v2/service/kms v1.23.1 + github.com/aws/aws-sdk-go-v2/service/s3 v1.37.0 github.com/btcsuite/btcd/btcutil v1.1.3 github.com/burdiyan/kafkautil v0.0.0-20190131162249-eaf83ed22d5b github.com/docker/go-connections v0.4.0 @@ -55,7 +55,7 @@ require ( require ( github.com/MicahParks/keyfunc/v2 v2.1.0 // indirect github.com/avast/retry-go v3.0.0+incompatible // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.8 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect github.com/deckarep/golang-set/v2 v2.1.0 // indirect @@ -98,18 +98,18 @@ require ( github.com/Microsoft/go-winio v0.6.0 // indirect github.com/avast/retry-go/v4 v4.3.3 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.13.20 - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.33 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.24 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.13.27 + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.27 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.27 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.26 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.1 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.12.8 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.18.9 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.30 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.12.13 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.19.3 // indirect github.com/aws/smithy-go v1.13.5 // indirect github.com/bsm/redislock v0.7.2 // indirect github.com/capnm/sysinfo v0.0.0-20130621111458-5909a53897f3 // indirect diff --git a/go.sum b/go.sum index 9a9a0c54a..fc41c9de9 100644 --- a/go.sum +++ b/go.sum @@ -54,6 +54,7 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0/go.mod h1:+6sju8gk8FRmSajX3Oz4G5Gm7P+mbqE9FVaXXFYTkCM= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= @@ -92,6 +93,7 @@ github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4Oe github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/Microsoft/hcsshim v0.9.7 h1:mKNHW/Xvv1aFH87Jb6ERDzXTJTLPlmzfZ28VBFD/bfg= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= @@ -136,42 +138,74 @@ github.com/aws/aws-sdk-go v1.43.45 h1:2708Bj4uV+ym62MOtBnErm/CDX61C4mFe9V2gXy1ca github.com/aws/aws-sdk-go-v2 v1.17.6/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2 v1.17.8 h1:GMupCNNI7FARX27L7GjCJM8NgivWbRgpjNI/hOQjFS8= github.com/aws/aws-sdk-go-v2 v1.17.8/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2 v1.19.0 h1:klAT+y3pGFBU/qVf1uzwttpBbiuozJYWzNLHioyDJ+k= +github.com/aws/aws-sdk-go-v2 v1.19.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno= github.com/aws/aws-sdk-go-v2/config v1.18.21 h1:ENTXWKwE8b9YXgQCsruGLhvA9bhg+RqAsL9XEMEsa2c= github.com/aws/aws-sdk-go-v2/config v1.18.21/go.mod h1:+jPQiVPz1diRnjj6VGqWcLK6EzNmQ42l7J3OqGTLsSY= +github.com/aws/aws-sdk-go-v2/config v1.18.28 h1:TINEaKyh1Td64tqFvn09iYpKiWjmHYrG1fa91q2gnqw= +github.com/aws/aws-sdk-go-v2/config v1.18.28/go.mod h1:nIL+4/8JdAuNHEjn/gPEXqtnS02Q3NXB/9Z7o5xE4+A= github.com/aws/aws-sdk-go-v2/credentials v1.13.20 h1:oZCEFcrMppP/CNiS8myzv9JgOzq2s0d3v3MXYil/mxQ= github.com/aws/aws-sdk-go-v2/credentials v1.13.20/go.mod h1:xtZnXErtbZ8YGXC3+8WfajpMBn5Ga/3ojZdxHq6iI8o= +github.com/aws/aws-sdk-go-v2/credentials v1.13.27 h1:dz0yr/yR1jweAnsCx+BmjerUILVPQ6FS5AwF/OyG1kA= +github.com/aws/aws-sdk-go-v2/credentials v1.13.27/go.mod h1:syOqAek45ZXZp29HlnRS/BNgMIW6uiRmeuQsz4Qh2UE= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.2 h1:jOzQAesnBFDmz93feqKnsTHsXrlwWORNZMFHMV+WLFU= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.2/go.mod h1:cDh1p6XkSGSwSRIArWRc6+UqAQ7x4alQ0QfpVR6f+co= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5 h1:kP3Me6Fy3vdi+9uHd7YLr6ewPxRL+PU6y15urfTaamU= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5/go.mod h1:Gj7tm95r+QsDoN2Fhuz/3npQvcZbkEf5mL70n3Xfluc= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30/go.mod h1:LUBAO3zNXQjoONBKn/kR1y0Q4cj/D02Ts0uHYjcCQLM= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32 h1:dpbVNUjczQ8Ae3QKHbpHBpfvaVkRdesxpTOe9pTouhU= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32/go.mod h1:RudqOgadTWdcS3t/erPQo24pcVEoYyqj/kKW5Vya21I= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35 h1:hMUCiE3Zi5AHrRNGf5j985u0WyqI6r2NULhUfo0N/No= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35/go.mod h1:ipR5PvpSPqIqL5Mi82BxLnfMkHVbmco8kUwO2xrCi0M= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24/go.mod h1:gAuCezX/gob6BSMbItsSlMb6WZGV7K2+fWOvk8xBSto= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26 h1:QH2kOS3Ht7x+u0gHCh06CXL/h6G8LQJFpZfFBYBNboo= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26/go.mod h1:vq86l7956VgFr0/FWQ2BWnK07QC3WYsepKzy33qqY5U= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29 h1:yOpYx+FTBdpk/g+sBU6Cb1H0U/TLEcYYp66mYqsPpcc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29/go.mod h1:M/eUABlDbw2uVrdAn+UsI6M727qp2fxkp8K0ejcBDUY= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.33 h1:HbH1VjUgrCdLJ+4lnnuLI4iVNRvBbBELGaJ5f69ClA8= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.33/go.mod h1:zG2FcwjQarWaqXSCGpgcr3RSjZ6dHGguZSppUL0XR7Q= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36 h1:8r5m1BoAWkn0TDC34lUculryf7nUF25EgIMdjvGCkgo= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36/go.mod h1:Rmw2M1hMVTwiUhjwMoIBFWFJMhvJbct06sSidxInkhY= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.24 h1:zsg+5ouVLLbePknVZlUMm1ptwyQLkjjLMWnN+kVs5dA= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.24/go.mod h1:+fFaIjycTmpV6hjmPTbyU9Kp5MI/lA+bbibcAtmlhYA= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.27 h1:cZG7psLfqpkB6H+fIrgUDWmlzM474St1LP0jcz272yI= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.27/go.mod h1:ZdjYvJpDlefgh8/hWelJhqgqJeodxu4SmbVsSdBlL7E= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.27 h1:qIw7Hg5eJEc1uSxg3hRwAthPAO7NeOd4dPxhaTi0yB0= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.27/go.mod h1:Zz0kvhcSlu3NX4XJkaGgdjaa+u7a9LYuy8JKxA5v3RM= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.30 h1:Bje8Xkh2OWpjBdNfXLrnn8eZg569dUQmhgtydxAYyP0= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.30/go.mod h1:qQtIBl5OVMfmeQkz8HaVyh5DzFmmFXyvK27UgIgOr4c= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.26 h1:uUt4XctZLhl9wBE1L8lobU3bVN8SNUP7T+olb0bWBO4= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.26/go.mod h1:Bd4C/4PkVGubtNe5iMXu5BNnaBi/9t/UsFspPt4ram8= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29 h1:IiDolu/eLmuB18DRZibj77n1hHQT7z12jnGO7Ze3pLc= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29/go.mod h1:fDbkK4o7fpPXWn8YAPmTieAMuB9mk/VgvW64uaUqxd4= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.1 h1:lRWp3bNu5wy0X3a8GS42JvZFlv++AKsMdzEnoiVJrkg= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.1/go.mod h1:VXBHSxdN46bsJrkniN68psSwbyBKsazQfU2yX/iSDso= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.4 h1:hx4WksB0NRQ9utR+2c3gEGzl6uKj3eM6PMQ6tN3lgXs= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.4/go.mod h1:JniVpqvw90sVjNqanGLufrVapWySL28fhBlYgl96Q/w= github.com/aws/aws-sdk-go-v2/service/kms v1.20.7 h1:7Ligq/4Mei9qZScT1p51REuqq0dB8MLOIs8X/tsLfB0= github.com/aws/aws-sdk-go-v2/service/kms v1.20.7/go.mod h1:1OnRDyIEZ/RFBhxzu9oFZ3zV0RU0I9GWT3Dxz3pgITU= +github.com/aws/aws-sdk-go-v2/service/kms v1.23.1 h1:u9A03kEyjBCt44Tg3NMtWJL2SnIvMpipDIoQYtXYzMA= +github.com/aws/aws-sdk-go-v2/service/kms v1.23.1/go.mod h1:BuDl6WtqaDJbd9c29q/EFHrZjuWlrJN7oMNy5Yd5n7Q= github.com/aws/aws-sdk-go-v2/service/s3 v1.31.3 h1:MG+2UlhyBL3oCOoHbUQh+Sqr3elN0I5PBe0MtVh0xMg= github.com/aws/aws-sdk-go-v2/service/s3 v1.31.3/go.mod h1:aSl9/LJltSz1cVusiR/Mu8tvI4Sv/5w/WWrJmmkNii0= +github.com/aws/aws-sdk-go-v2/service/s3 v1.37.0 h1:PalLOEGZ/4XfQxpGZFTLaoJSmPoybnqJYotaIZEf/Rg= +github.com/aws/aws-sdk-go-v2/service/s3 v1.37.0/go.mod h1:PwyKKVL0cNkC37QwLcrhyeCrAk+5bY8O2ou7USyAS2A= github.com/aws/aws-sdk-go-v2/service/sso v1.12.8 h1:5cb3D6xb006bPTqEfCNaEA6PPEfBXxxy4NNeX/44kGk= github.com/aws/aws-sdk-go-v2/service/sso v1.12.8/go.mod h1:GNIveDnP+aE3jujyUSH5aZ/rktsTM5EvtKnCqBZawdw= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.13 h1:sWDv7cMITPcZ21QdreULwxOOAmE05JjEsT6fCDtDA9k= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.13/go.mod h1:DfX0sWuT46KpcqbMhJ9QWtxAIP1VozkDWf8VAkByjYY= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.8 h1:NZaj0ngZMzsubWZbrEFSB4rgSQRbFq38Sd6KBxHuOIU= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.8/go.mod h1:44qFP1g7pfd+U+sQHLPalAPKnyfTZjJsYR4xIwsJy5o= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13 h1:BFubHS/xN5bjl818QaroN6mQdjneYQ+AOx44KNXlyH4= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13/go.mod h1:BzqsVVFduubEmzrVtUFQQIQdFqvUItF8XUq2EnS8Wog= github.com/aws/aws-sdk-go-v2/service/sts v1.18.9 h1:Qf1aWwnsNkyAoqDqmdM3nHwN78XQjec27LjM6b9vyfI= github.com/aws/aws-sdk-go-v2/service/sts v1.18.9/go.mod h1:yyW88BEPXA2fGFyI2KCcZC3dNpiT0CZAHaF+i656/tQ= +github.com/aws/aws-sdk-go-v2/service/sts v1.19.3 h1:e5mnydVdCVWxP+5rPAGi2PYxC7u2OZgH1ypC114H04U= +github.com/aws/aws-sdk-go-v2/service/sts v1.19.3/go.mod h1:yVGZA1CPkmUhBdA039jXNJJG7/6t+G+EBWmFq23xqnY= github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -180,6 +214,7 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bsm/redislock v0.7.2 h1:jggqOio8JyX9FJBKIfjF3fTxAu/v7zC5mAID9LveqG4= github.com/bsm/redislock v0.7.2/go.mod h1:kS2g0Yvlymc9Dz8V3iVYAtLAaSVruYbAFdYBDrmC5WU= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= @@ -242,10 +277,25 @@ github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5b github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= +github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/cgroups v1.0.4/go.mod h1:nLNQtsF7Sl2HxNebu77i1R0oDlhiTG+kO4JTrUzo6IA= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/containerd v1.6.19 h1:F0qgQPrG0P2JPgwpxWxYavrVeXAG0ezUIB9Z/4FTUAU= github.com/containerd/containerd v1.6.19/go.mod h1:HZCDMn4v/Xl2579/MvtOC2M206i+JJ6VxFWU/NetrGY= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= +github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= +github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/go-cni v1.1.6/go.mod h1:BWtoWl5ghVymxu6MBjg79W9NZrCRyHIdUtk4cauMe34= +github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/imgcrypt v1.1.4/go.mod h1:LorQnPtzL/T0IyCeftcsMEO7AqxUDbdO8j/tSUpgxvo= +github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ= +github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= +github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containernetworking/cni v1.1.1/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= +github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19sZPp3ry5uHSkI4LPxV8= +github.com/containers/ocicrypt v1.1.3/go.mod h1:xpdkbVAuaH3WzbEabUd5yDsl9SwJA5pABH85425Es2g= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -274,12 +324,15 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE= github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v23.0.1+incompatible h1:vjgvJZxprTTE1A37nm+CLNAdwu6xZekyoiVlUZEINcY= github.com/docker/docker v23.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -299,6 +352,7 @@ github.com/elastic/elastic-transport-go/v8 v8.1.0 h1:NeqEz1ty4RQz+TVbUrpSU7pZ48X github.com/elastic/elastic-transport-go/v8 v8.1.0/go.mod h1:87Tcz8IVNe6rVSLdBux1o/PEItLtyabHU3naC7IoqKI= github.com/elastic/go-elasticsearch/v8 v8.6.0 h1:xMaSe8jIh7NHzmNo9YBkewmaD2Pr+tX+zLkXxhieny4= github.com/elastic/go-elasticsearch/v8 v8.6.0/go.mod h1:Usvydt+x0dv9a1TzEUaovqbJor8rmOHy5dSmPeMAE2k= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -343,6 +397,8 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -386,6 +442,7 @@ github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc= github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -456,6 +513,7 @@ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8 github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -476,6 +534,7 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -553,6 +612,7 @@ github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ= github.com/iron-io/iron_go3 v0.0.0-20190916120531-a4a7f74b73ac h1:w5wltlINIIqRTqQ64dASrCo0fM7k9nosPbKCZnkL0W0= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jarcoal/httpmock v1.1.0 h1:F47ChZj1Y2zFsCXxNkBPwNNKnAyOATcdQibk0qEdVCE= @@ -661,8 +721,10 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfr github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= @@ -675,11 +737,17 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo= github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/sys/mount v0.3.3/go.mod h1:PBaEorSNTLG5t/+4EgukEQVlAvVEc6ZjTySwKdqp5K0= github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/sys/signal v0.6.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= +github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs= github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -732,6 +800,7 @@ github.com/opencontainers/runc v1.1.4 h1:nRCz/8sKg6K6jgYAFLDlXzPeITBZJyX28DBVhWD github.com/opencontainers/runc v1.1.4/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -817,6 +886,7 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4= github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8= github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4= @@ -851,6 +921,7 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -877,6 +948,7 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/testcontainers/testcontainers-go v0.19.0 h1:3bmFPuQRgVIQwxZJERyzB8AogmJW3Qzh8iDyfJbPhi8= github.com/testcontainers/testcontainers-go v0.19.0/go.mod h1:3YsSoxK0rGEUzbGD4gUVt1Nm3GJpCIq94GX+2LSf3d4= github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= @@ -896,6 +968,7 @@ github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hM github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= @@ -904,7 +977,9 @@ github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= @@ -925,6 +1000,8 @@ github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23n github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -933,10 +1010,13 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU= go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -944,7 +1024,13 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0/go.mod h1:vEhqr0m4eTc+DWxfsXoXue2GBgV2uUwVznkGIHW/e5w= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDDKDkvI9dP/FIhpmna5lkqPUQdEjFAM8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0/go.mod h1:keUU7UfnwWTWpJ+FWnyqmogPa82nuU5VUANFq49hlMY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0/go.mod h1:QNX1aly8ehqqX1LEa6YniTU7VY9I6R3X/oPxhGdTceE= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/automaxprocs v1.5.1 h1:e1YG66Lrk73dn4qhg8WFSvhF0JuFQF0ERIp4rpuV8Qk= go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU= @@ -1520,9 +1606,11 @@ gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mN gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= gopkg.in/jcmturner/gokrb5.v7 v7.4.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/redis.v5 v5.2.9/go.mod h1:6gtv0/+A4iM08kdRfocWYB3bLX2tebpNtfKlFT6H4mY= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1548,6 +1636,13 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs= +k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U= +k8s.io/apiserver v0.22.5/go.mod h1:s2WbtgZAkTKt679sYtSudEQrTGWUSQAPe6MupLnlmaQ= +k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y= +k8s.io/component-base v0.22.5/go.mod h1:VK3I+TjuF9eaa+Ln67dKxhGar5ynVbwnGrUiNF4MqCI= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= @@ -1596,5 +1691,6 @@ modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/internal/controllers/user_devices_controller.go b/internal/controllers/user_devices_controller.go index 955b947b8..b98964aea 100644 --- a/internal/controllers/user_devices_controller.go +++ b/internal/controllers/user_devices_controller.go @@ -1919,9 +1919,7 @@ func (udc *UserDevicesController) PostMintDevice(c *fiber.Ctx) error { childNum := seq.NextVal - var wallet services.SyntheticWalletInstanceService - - addr, err := wallet.GetAddress(c.Context(), uint32(childNum)) + addr, err := udc.wallet.GetAddress(c.Context(), uint32(childNum)) if err != nil { return err } @@ -1935,7 +1933,7 @@ func (udc *UserDevicesController) PostMintDevice(c *fiber.Ctx) error { return err } - sign, err := wallet.SignHash(c.Context(), uint32(childNum), hash.Bytes()) + sign, err := udc.wallet.SignHash(c.Context(), uint32(childNum), hash.Bytes()) if err != nil { return err } diff --git a/settings.sample.yaml b/settings.sample.yaml index a3f079a11..bbbcdb03d 100644 --- a/settings.sample.yaml +++ b/settings.sample.yaml @@ -35,6 +35,8 @@ AUTO_PI_API_URL: DOCUMENTS_AWS_ACCESS_KEY_ID: test DOCUMENTS_AWS_SECRET_ACCESS_KEY: test DOCUMENTS_AWS_ENDPOINT: http://localhost:4566 +NFT_AWS_ACCESS_KEY_ID: test +NFT_AWS_SECRET_ACCESS_KEY: test DRIVLY_VIN_API_URL: https://vin.dev.driv.ly DRIVLY_OFFER_API_URL: https://offers.dev.driv.ly DRIVLY_API_KEY: xxx @@ -67,3 +69,6 @@ SYNTHETIC_DEVICES_ENABLED: true SYNTHETIC_WALLET_GRPC_ADDR: localhost:9006 DEVICE_DATA_GRPC_ADDR: localhost:8282 + +DEVICE_FINGERPRINT_TOPIC: topic.device.fingerprint +DEVICE_FINGERPRINT_CONSUMER_GROUP: device-fingerprint-vc-issuer \ No newline at end of file From 95404c1b59d3b1e0333289bb4b220f9253c0d3e6 Mon Sep 17 00:00:00 2001 From: Dylan Moreland Date: Mon, 24 Jul 2023 21:02:54 -0400 Subject: [PATCH 06/11] API up --- .../synthetic_devices_controller.go | 8 +- .../controllers/user_devices_controller.go | 37 +++- .../user_integrations_controller.go | 16 +- internal/services/registry/storage.go | 2 +- .../20230720215147_synthetic_multi_mint.sql | 2 +- models/synthetic_devices.go | 23 +- models/vehicle_nfts.go | 203 +++++++----------- 7 files changed, 130 insertions(+), 161 deletions(-) diff --git a/internal/controllers/synthetic_devices_controller.go b/internal/controllers/synthetic_devices_controller.go index f9dcd85fd..552602261 100644 --- a/internal/controllers/synthetic_devices_controller.go +++ b/internal/controllers/synthetic_devices_controller.go @@ -108,7 +108,7 @@ func (sdc *SyntheticDevicesController) GetSyntheticDeviceMintingPayload(c *fiber integrationID := c.Params("integrationID") ud, err := models.UserDevices( models.UserDeviceWhere.ID.EQ(userDeviceID), - qm.Load(qm.Rels(models.UserDeviceRels.VehicleNFT, models.VehicleNFTRels.VehicleTokenSyntheticDevices)), + qm.Load(qm.Rels(models.UserDeviceRels.VehicleNFT, models.VehicleNFTRels.VehicleTokenSyntheticDevice)), qm.Load(models.UserDeviceRels.UserDeviceAPIIntegrations, models.UserDeviceAPIIntegrationWhere.IntegrationID.EQ(integrationID)), ).One(c.Context(), sdc.DBS().Reader) if err != nil { @@ -119,7 +119,7 @@ func (sdc *SyntheticDevicesController) GetSyntheticDeviceMintingPayload(c *fiber return fiber.NewError(fiber.StatusConflict, "Vehicle not minted.") } - if ud.R.VehicleNFT.R.VehicleTokenSyntheticDevices != nil { + if ud.R.VehicleNFT.R.VehicleTokenSyntheticDevice != nil { return fiber.NewError(fiber.StatusConflict, "Vehicle already paired with a synthetic device.") } @@ -164,7 +164,7 @@ func (sdc *SyntheticDevicesController) MintSyntheticDevice(c *fiber.Ctx) error { ud, err := models.UserDevices( models.UserDeviceWhere.ID.EQ(userDeviceID), - qm.Load(qm.Rels(models.UserDeviceRels.VehicleNFT, models.VehicleNFTRels.VehicleTokenSyntheticDevices)), + qm.Load(qm.Rels(models.UserDeviceRels.VehicleNFT, models.VehicleNFTRels.VehicleTokenSyntheticDevice)), qm.Load(models.UserDeviceRels.UserDeviceAPIIntegrations, models.UserDeviceAPIIntegrationWhere.IntegrationID.EQ(integrationID)), ).One(c.Context(), sdc.DBS().Reader) if err != nil { @@ -175,7 +175,7 @@ func (sdc *SyntheticDevicesController) MintSyntheticDevice(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusConflict, "Vehicle not minted.") } - if ud.R.VehicleNFT.R.VehicleTokenSyntheticDevices != nil { + if ud.R.VehicleNFT.R.VehicleTokenSyntheticDevice != nil { return fiber.NewError(fiber.StatusConflict, "Vehicle already paired with a synthetic device.") } diff --git a/internal/controllers/user_devices_controller.go b/internal/controllers/user_devices_controller.go index b98964aea..b9adcde90 100644 --- a/internal/controllers/user_devices_controller.go +++ b/internal/controllers/user_devices_controller.go @@ -230,6 +230,8 @@ func (udc *UserDevicesController) dbDevicesToDisplay(ctx context.Context, device } } + var sdStat *SyntheticDeviceStatus + var nft *NFTData pu := []PrivilegeUser{} @@ -277,6 +279,22 @@ func (udc *UserDevicesController) dbDevicesToDisplay(ctx context.Context, device Privileges: v, }) } + + if sd := vnft.R.VehicleTokenSyntheticDevice; sd != nil { + ii, _ := sd.IntegrationTokenID.Uint64() + mtr := sd.R.MintRequest + sdStat = &SyntheticDeviceStatus{ + IntegrationID: ii, + Status: mtr.Status, + } + if mtr.Hash.Valid { + h := hexutil.Encode(mtr.Hash.Bytes) + sdStat.TxHash = &h + } + if !sd.TokenID.IsZero() { + sdStat.TokenID = sd.TokenID.Int(nil) + } + } } udf := UserDeviceFull{ @@ -287,7 +305,7 @@ func (udc *UserDevicesController) dbDevicesToDisplay(ctx context.Context, device CustomImageURL: d.CustomImageURL.Ptr(), CountryCode: d.CountryCode.Ptr(), DeviceDefinition: dd, - Integrations: NewUserDeviceIntegrationStatusesFromDatabase(d.R.UserDeviceAPIIntegrations, integrations), + Integrations: NewUserDeviceIntegrationStatusesFromDatabase(d.R.UserDeviceAPIIntegrations, integrations, sdStat), Metadata: md, NFT: nft, OptedInAt: d.OptedInAt.Ptr(), @@ -331,7 +349,7 @@ func (udc *UserDevicesController) GetUserDevices(c *fiber.Ctx) error { query = append(query, qm.Load(models.UserDeviceRels.UserDeviceAPIIntegrations), qm.Load(qm.Rels(models.UserDeviceRels.VehicleNFT, models.VehicleNFTRels.MintRequest)), - qm.Load(qm.Rels(models.UserDeviceRels.VehicleNFT, models.VehicleNFTRels.VehicleTokenSyntheticDevices, models.SyntheticDeviceRels.MintRequest)), + qm.Load(qm.Rels(models.UserDeviceRels.VehicleNFT, models.VehicleNFTRels.VehicleTokenSyntheticDevice, models.SyntheticDeviceRels.MintRequest)), qm.OrderBy(models.UserDeviceColumns.CreatedAt+" DESC")) devices, err := models.UserDevices(query...).All(c.Context(), udc.DBS().Reader) @@ -411,6 +429,7 @@ func (udc *UserDevicesController) GetSharedDevices(c *fiber.Ctx) error { qm.Load(models.UserDeviceRels.UserDeviceAPIIntegrations), // Would we get this backreference for free? qm.Load(qm.Rels(models.UserDeviceRels.VehicleNFT, models.VehicleNFTRels.MintRequest)), + qm.Load(qm.Rels(models.UserDeviceRels.VehicleNFT, models.VehicleNFTRels.VehicleTokenSyntheticDevice, models.SyntheticDeviceRels.MintRequest)), ).One(c.Context(), udc.DBS().Reader) if err != nil { return err @@ -428,7 +447,7 @@ func (udc *UserDevicesController) GetSharedDevices(c *fiber.Ctx) error { return c.JSON(MyDevicesResp{SharedDevices: apiSharedDevices}) } -func NewUserDeviceIntegrationStatusesFromDatabase(udis []*models.UserDeviceAPIIntegration, integrations []*ddgrpc.Integration) []UserDeviceIntegrationStatus { +func NewUserDeviceIntegrationStatusesFromDatabase(udis []*models.UserDeviceAPIIntegration, integrations []*ddgrpc.Integration, sdStat *SyntheticDeviceStatus) []UserDeviceIntegrationStatus { out := make([]UserDeviceIntegrationStatus, len(udis)) for i, udi := range udis { @@ -447,6 +466,10 @@ func NewUserDeviceIntegrationStatusesFromDatabase(udis []*models.UserDeviceAPIIn for _, integration := range integrations { if integration.Id == udi.IntegrationID { out[i].IntegrationVendor = integration.Vendor + + if sdStat != nil && integration.TokenId == sdStat.IntegrationID { + out[i].Mint = sdStat + } break } } @@ -1958,6 +1981,7 @@ func (udc *UserDevicesController) PostMintDevice(c *fiber.Ctx) error { IntegrationNode: new(big.Int).SetUint64(intID), VehicleOwnerSig: sigBytes, SyntheticDeviceSig: sign, + SyntheticDeviceAddr: common.BytesToAddress(addr), AttrInfoPairsDevice: []contracts.AttributeInfoPair{}, }) } @@ -2163,3 +2187,10 @@ type NFTData struct { // Status is the minting status of the NFT. Status string `json:"status" enums:"Unstarted,Submitted,Mined,Confirmed" example:"Confirmed"` } + +type SyntheticDeviceStatus struct { + IntegrationID uint64 `json:"-"` + TokenID *big.Int `json:"tokenId,omitempty"` + TxHash *string `json:"txHash,omitempty" example:"0x30bce3da6985897224b29a0fe064fd2b426bb85a394cc09efe823b5c83326a8e"` + Status string `json:"status" enums:"Unstarted,Submitted,Mined,Confirmed" example:"Confirmed"` +} diff --git a/internal/controllers/user_integrations_controller.go b/internal/controllers/user_integrations_controller.go index 1751e9b57..ee31323a0 100644 --- a/internal/controllers/user_integrations_controller.go +++ b/internal/controllers/user_integrations_controller.go @@ -2022,13 +2022,15 @@ func fixTeslaDeviceDefinition(ctx context.Context, logger *zerolog.Logger, ddSvc /** Structs for request / response **/ type UserDeviceIntegrationStatus struct { - IntegrationID string `json:"integrationId"` - Status string `json:"status"` - CreatedAt time.Time `json:"createdAt"` - ExternalID *string `json:"externalId"` - UpdatedAt time.Time `json:"updatedAt"` - Metadata null.JSON `json:"metadata" swaggertype:"string"` - IntegrationVendor string `json:"integrationVendor"` + IntegrationID string `json:"integrationId"` + Status string `json:"status"` + CreatedAt time.Time `json:"createdAt"` + ExternalID *string `json:"externalId"` + UpdatedAt time.Time `json:"updatedAt"` + Metadata null.JSON `json:"metadata" swaggertype:"string"` + IntegrationVendor string `json:"integrationVendor"` + Mint *SyntheticDeviceStatus `json:"syntheticDevice,omitempty"` + TokenID *big.Int `json:"tokenId,omitempty"` } // RegisterDeviceIntegrationRequest carries credentials used to connect the device to a given diff --git a/internal/services/registry/storage.go b/internal/services/registry/storage.go index 5ffa21bbe..c57bdeff9 100644 --- a/internal/services/registry/storage.go +++ b/internal/services/registry/storage.go @@ -103,7 +103,7 @@ func (p *proc) Handle(ctx context.Context, data *ceData) error { logger.Info().Str("userDeviceId", mtr.R.MintRequestVehicleNFT.UserDeviceID.String).Msg("Vehicle minted.") } else if l1.Topics[0] == syntheticDeviceMintedEvent.ID { // We must be doing a combined vehicle and SD mint. This always comes second. - var out contracts.RegistrySyntheticDeviceNodeMinted + out := new(contracts.RegistrySyntheticDeviceNodeMinted) sd := mtr.R.MintRequestSyntheticDevice if sd == nil { diff --git a/migrations/20230720215147_synthetic_multi_mint.sql b/migrations/20230720215147_synthetic_multi_mint.sql index 6a6f9bca4..572a23662 100644 --- a/migrations/20230720215147_synthetic_multi_mint.sql +++ b/migrations/20230720215147_synthetic_multi_mint.sql @@ -2,9 +2,9 @@ -- +goose StatementBegin SET search_path = devices_api, public; -ALTER TABLE synthetic_devices ADD CONSTRAINT synthetic_devices_vehicle_token_id_integration_token_id_key UNIQUE (vehicle_token_id, integration_token_id); ALTER TABLE synthetic_devices DROP CONSTRAINT synthetic_devices_pkey; ALTER TABLE synthetic_devices ALTER COLUMN vehicle_token_id DROP NOT NULL; +ALTER TABLE synthetic_devices ADD CONSTRAINT synthetic_devices_vehicle_token_id_key UNIQUE (vehicle_token_id); ALTER TABLE synthetic_devices ADD CONSTRAINT synthetic_devices_pkey PRIMARY KEY (mint_request_id); -- +goose StatementEnd diff --git a/models/synthetic_devices.go b/models/synthetic_devices.go index 49253e1dd..c1e2d3633 100644 --- a/models/synthetic_devices.go +++ b/models/synthetic_devices.go @@ -706,7 +706,7 @@ func (syntheticDeviceL) LoadVehicleToken(ctx context.Context, e boil.ContextExec if foreign.R == nil { foreign.R = &vehicleNFTR{} } - foreign.R.VehicleTokenSyntheticDevices = append(foreign.R.VehicleTokenSyntheticDevices, object) + foreign.R.VehicleTokenSyntheticDevice = object return nil } @@ -717,7 +717,7 @@ func (syntheticDeviceL) LoadVehicleToken(ctx context.Context, e boil.ContextExec if foreign.R == nil { foreign.R = &vehicleNFTR{} } - foreign.R.VehicleTokenSyntheticDevices = append(foreign.R.VehicleTokenSyntheticDevices, local) + foreign.R.VehicleTokenSyntheticDevice = local break } } @@ -899,7 +899,7 @@ func (o *SyntheticDevice) SetMintRequest(ctx context.Context, exec boil.ContextE // SetVehicleToken of the syntheticDevice to the related item. // Sets o.R.VehicleToken to related. -// Adds o to related.R.VehicleTokenSyntheticDevices. +// Adds o to related.R.VehicleTokenSyntheticDevice. func (o *SyntheticDevice) SetVehicleToken(ctx context.Context, exec boil.ContextExecutor, insert bool, related *VehicleNFT) error { var err error if insert { @@ -935,10 +935,10 @@ func (o *SyntheticDevice) SetVehicleToken(ctx context.Context, exec boil.Context if related.R == nil { related.R = &vehicleNFTR{ - VehicleTokenSyntheticDevices: SyntheticDeviceSlice{o}, + VehicleTokenSyntheticDevice: o, } } else { - related.R.VehicleTokenSyntheticDevices = append(related.R.VehicleTokenSyntheticDevices, o) + related.R.VehicleTokenSyntheticDevice = o } return nil @@ -962,18 +962,7 @@ func (o *SyntheticDevice) RemoveVehicleToken(ctx context.Context, exec boil.Cont return nil } - for i, ri := range related.R.VehicleTokenSyntheticDevices { - if queries.Equal(o.VehicleTokenID, ri.VehicleTokenID) { - continue - } - - ln := len(related.R.VehicleTokenSyntheticDevices) - if ln > 1 && i < ln-1 { - related.R.VehicleTokenSyntheticDevices[i] = related.R.VehicleTokenSyntheticDevices[ln-1] - } - related.R.VehicleTokenSyntheticDevices = related.R.VehicleTokenSyntheticDevices[:ln-1] - break - } + related.R.VehicleTokenSyntheticDevice = nil return nil } diff --git a/models/vehicle_nfts.go b/models/vehicle_nfts.go index a2d5d350a..2d4c3918e 100644 --- a/models/vehicle_nfts.go +++ b/models/vehicle_nfts.go @@ -92,13 +92,13 @@ var VehicleNFTRels = struct { MintRequest string UserDevice string VehicleTokenAftermarketDevice string - VehicleTokenSyntheticDevices string + VehicleTokenSyntheticDevice string }{ Claim: "Claim", MintRequest: "MintRequest", UserDevice: "UserDevice", VehicleTokenAftermarketDevice: "VehicleTokenAftermarketDevice", - VehicleTokenSyntheticDevices: "VehicleTokenSyntheticDevices", + VehicleTokenSyntheticDevice: "VehicleTokenSyntheticDevice", } // vehicleNFTR is where relationships are stored. @@ -107,7 +107,7 @@ type vehicleNFTR struct { MintRequest *MetaTransactionRequest `boil:"MintRequest" json:"MintRequest" toml:"MintRequest" yaml:"MintRequest"` UserDevice *UserDevice `boil:"UserDevice" json:"UserDevice" toml:"UserDevice" yaml:"UserDevice"` VehicleTokenAftermarketDevice *AftermarketDevice `boil:"VehicleTokenAftermarketDevice" json:"VehicleTokenAftermarketDevice" toml:"VehicleTokenAftermarketDevice" yaml:"VehicleTokenAftermarketDevice"` - VehicleTokenSyntheticDevices SyntheticDeviceSlice `boil:"VehicleTokenSyntheticDevices" json:"VehicleTokenSyntheticDevices" toml:"VehicleTokenSyntheticDevices" yaml:"VehicleTokenSyntheticDevices"` + VehicleTokenSyntheticDevice *SyntheticDevice `boil:"VehicleTokenSyntheticDevice" json:"VehicleTokenSyntheticDevice" toml:"VehicleTokenSyntheticDevice" yaml:"VehicleTokenSyntheticDevice"` } // NewStruct creates a new relationship struct @@ -143,11 +143,11 @@ func (r *vehicleNFTR) GetVehicleTokenAftermarketDevice() *AftermarketDevice { return r.VehicleTokenAftermarketDevice } -func (r *vehicleNFTR) GetVehicleTokenSyntheticDevices() SyntheticDeviceSlice { +func (r *vehicleNFTR) GetVehicleTokenSyntheticDevice() *SyntheticDevice { if r == nil { return nil } - return r.VehicleTokenSyntheticDevices + return r.VehicleTokenSyntheticDevice } // vehicleNFTL is where Load methods for each relationship are stored. @@ -483,16 +483,13 @@ func (o *VehicleNFT) VehicleTokenAftermarketDevice(mods ...qm.QueryMod) aftermar return AftermarketDevices(queryMods...) } -// VehicleTokenSyntheticDevices retrieves all the synthetic_device's SyntheticDevices with an executor via vehicle_token_id column. -func (o *VehicleNFT) VehicleTokenSyntheticDevices(mods ...qm.QueryMod) syntheticDeviceQuery { - var queryMods []qm.QueryMod - if len(mods) != 0 { - queryMods = append(queryMods, mods...) +// VehicleTokenSyntheticDevice pointed to by the foreign key. +func (o *VehicleNFT) VehicleTokenSyntheticDevice(mods ...qm.QueryMod) syntheticDeviceQuery { + queryMods := []qm.QueryMod{ + qm.Where("\"vehicle_token_id\" = ?", o.TokenID), } - queryMods = append(queryMods, - qm.Where("\"devices_api\".\"synthetic_devices\".\"vehicle_token_id\"=?", o.TokenID), - ) + queryMods = append(queryMods, mods...) return SyntheticDevices(queryMods...) } @@ -982,9 +979,9 @@ func (vehicleNFTL) LoadVehicleTokenAftermarketDevice(ctx context.Context, e boil return nil } -// LoadVehicleTokenSyntheticDevices allows an eager lookup of values, cached into the -// loaded structs of the objects. This is for a 1-M or N-M relationship. -func (vehicleNFTL) LoadVehicleTokenSyntheticDevices(ctx context.Context, e boil.ContextExecutor, singular bool, maybeVehicleNFT interface{}, mods queries.Applicator) error { +// LoadVehicleTokenSyntheticDevice allows an eager lookup of values, cached into the +// loaded structs of the objects. This is for a 1-1 relationship. +func (vehicleNFTL) LoadVehicleTokenSyntheticDevice(ctx context.Context, e boil.ContextExecutor, singular bool, maybeVehicleNFT interface{}, mods queries.Applicator) error { var slice []*VehicleNFT var object *VehicleNFT @@ -1047,16 +1044,16 @@ func (vehicleNFTL) LoadVehicleTokenSyntheticDevices(ctx context.Context, e boil. results, err := query.QueryContext(ctx, e) if err != nil { - return errors.Wrap(err, "failed to eager load synthetic_devices") + return errors.Wrap(err, "failed to eager load SyntheticDevice") } var resultSlice []*SyntheticDevice if err = queries.Bind(results, &resultSlice); err != nil { - return errors.Wrap(err, "failed to bind eager loaded slice synthetic_devices") + return errors.Wrap(err, "failed to bind eager loaded slice SyntheticDevice") } if err = results.Close(); err != nil { - return errors.Wrap(err, "failed to close results in eager load on synthetic_devices") + return errors.Wrap(err, "failed to close results of eager load for synthetic_devices") } if err = results.Err(); err != nil { return errors.Wrap(err, "error occurred during iteration of eager loaded relations for synthetic_devices") @@ -1069,21 +1066,24 @@ func (vehicleNFTL) LoadVehicleTokenSyntheticDevices(ctx context.Context, e boil. } } } + + if len(resultSlice) == 0 { + return nil + } + if singular { - object.R.VehicleTokenSyntheticDevices = resultSlice - for _, foreign := range resultSlice { - if foreign.R == nil { - foreign.R = &syntheticDeviceR{} - } - foreign.R.VehicleToken = object + foreign := resultSlice[0] + object.R.VehicleTokenSyntheticDevice = foreign + if foreign.R == nil { + foreign.R = &syntheticDeviceR{} } - return nil + foreign.R.VehicleToken = object } - for _, foreign := range resultSlice { - for _, local := range slice { + for _, local := range slice { + for _, foreign := range resultSlice { if queries.Equal(local.TokenID, foreign.VehicleTokenID) { - local.R.VehicleTokenSyntheticDevices = append(local.R.VehicleTokenSyntheticDevices, foreign) + local.R.VehicleTokenSyntheticDevice = foreign if foreign.R == nil { foreign.R = &syntheticDeviceR{} } @@ -1355,129 +1355,76 @@ func (o *VehicleNFT) RemoveVehicleTokenAftermarketDevice(ctx context.Context, ex return nil } -// AddVehicleTokenSyntheticDevices adds the given related objects to the existing relationships -// of the vehicle_nft, optionally inserting them as new records. -// Appends related to o.R.VehicleTokenSyntheticDevices. -// Sets related.R.VehicleToken appropriately. -func (o *VehicleNFT) AddVehicleTokenSyntheticDevices(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*SyntheticDevice) error { +// SetVehicleTokenSyntheticDevice of the vehicleNFT to the related item. +// Sets o.R.VehicleTokenSyntheticDevice to related. +// Adds o to related.R.VehicleToken. +func (o *VehicleNFT) SetVehicleTokenSyntheticDevice(ctx context.Context, exec boil.ContextExecutor, insert bool, related *SyntheticDevice) error { var err error - for _, rel := range related { - if insert { - queries.Assign(&rel.VehicleTokenID, o.TokenID) - if err = rel.Insert(ctx, exec, boil.Infer()); err != nil { - return errors.Wrap(err, "failed to insert into foreign table") - } - } else { - updateQuery := fmt.Sprintf( - "UPDATE \"devices_api\".\"synthetic_devices\" SET %s WHERE %s", - strmangle.SetParamNames("\"", "\"", 1, []string{"vehicle_token_id"}), - strmangle.WhereClause("\"", "\"", 2, syntheticDevicePrimaryKeyColumns), - ) - values := []interface{}{o.TokenID, rel.MintRequestID} - - if boil.IsDebug(ctx) { - writer := boil.DebugWriterFrom(ctx) - fmt.Fprintln(writer, updateQuery) - fmt.Fprintln(writer, values) - } - if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { - return errors.Wrap(err, "failed to update foreign table") - } - queries.Assign(&rel.VehicleTokenID, o.TokenID) + if insert { + queries.Assign(&related.VehicleTokenID, o.TokenID) + + if err = related.Insert(ctx, exec, boil.Infer()); err != nil { + return errors.Wrap(err, "failed to insert into foreign table") + } + } else { + updateQuery := fmt.Sprintf( + "UPDATE \"devices_api\".\"synthetic_devices\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 1, []string{"vehicle_token_id"}), + strmangle.WhereClause("\"", "\"", 2, syntheticDevicePrimaryKeyColumns), + ) + values := []interface{}{o.TokenID, related.MintRequestID} + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, updateQuery) + fmt.Fprintln(writer, values) + } + if _, err = exec.ExecContext(ctx, updateQuery, values...); err != nil { + return errors.Wrap(err, "failed to update foreign table") } + + queries.Assign(&related.VehicleTokenID, o.TokenID) } if o.R == nil { o.R = &vehicleNFTR{ - VehicleTokenSyntheticDevices: related, + VehicleTokenSyntheticDevice: related, } } else { - o.R.VehicleTokenSyntheticDevices = append(o.R.VehicleTokenSyntheticDevices, related...) + o.R.VehicleTokenSyntheticDevice = related } - for _, rel := range related { - if rel.R == nil { - rel.R = &syntheticDeviceR{ - VehicleToken: o, - } - } else { - rel.R.VehicleToken = o + if related.R == nil { + related.R = &syntheticDeviceR{ + VehicleToken: o, } + } else { + related.R.VehicleToken = o } return nil } -// SetVehicleTokenSyntheticDevices removes all previously related items of the -// vehicle_nft replacing them completely with the passed -// in related items, optionally inserting them as new records. -// Sets o.R.VehicleToken's VehicleTokenSyntheticDevices accordingly. -// Replaces o.R.VehicleTokenSyntheticDevices with related. -// Sets related.R.VehicleToken's VehicleTokenSyntheticDevices accordingly. -func (o *VehicleNFT) SetVehicleTokenSyntheticDevices(ctx context.Context, exec boil.ContextExecutor, insert bool, related ...*SyntheticDevice) error { - query := "update \"devices_api\".\"synthetic_devices\" set \"vehicle_token_id\" = null where \"vehicle_token_id\" = $1" - values := []interface{}{o.TokenID} - if boil.IsDebug(ctx) { - writer := boil.DebugWriterFrom(ctx) - fmt.Fprintln(writer, query) - fmt.Fprintln(writer, values) - } - _, err := exec.ExecContext(ctx, query, values...) - if err != nil { - return errors.Wrap(err, "failed to remove relationships before set") - } - - if o.R != nil { - for _, rel := range o.R.VehicleTokenSyntheticDevices { - queries.SetScanner(&rel.VehicleTokenID, nil) - if rel.R == nil { - continue - } +// RemoveVehicleTokenSyntheticDevice relationship. +// Sets o.R.VehicleTokenSyntheticDevice to nil. +// Removes o from all passed in related items' relationships struct. +func (o *VehicleNFT) RemoveVehicleTokenSyntheticDevice(ctx context.Context, exec boil.ContextExecutor, related *SyntheticDevice) error { + var err error - rel.R.VehicleToken = nil - } - o.R.VehicleTokenSyntheticDevices = nil + queries.SetScanner(&related.VehicleTokenID, nil) + if _, err = related.Update(ctx, exec, boil.Whitelist("vehicle_token_id")); err != nil { + return errors.Wrap(err, "failed to update local table") } - return o.AddVehicleTokenSyntheticDevices(ctx, exec, insert, related...) -} - -// RemoveVehicleTokenSyntheticDevices relationships from objects passed in. -// Removes related items from R.VehicleTokenSyntheticDevices (uses pointer comparison, removal does not keep order) -// Sets related.R.VehicleToken. -func (o *VehicleNFT) RemoveVehicleTokenSyntheticDevices(ctx context.Context, exec boil.ContextExecutor, related ...*SyntheticDevice) error { - if len(related) == 0 { - return nil + if o.R != nil { + o.R.VehicleTokenSyntheticDevice = nil } - var err error - for _, rel := range related { - queries.SetScanner(&rel.VehicleTokenID, nil) - if rel.R != nil { - rel.R.VehicleToken = nil - } - if _, err = rel.Update(ctx, exec, boil.Whitelist("vehicle_token_id")); err != nil { - return err - } - } - if o.R == nil { + if related == nil || related.R == nil { return nil } - for _, rel := range related { - for i, ri := range o.R.VehicleTokenSyntheticDevices { - if rel != ri { - continue - } - - ln := len(o.R.VehicleTokenSyntheticDevices) - if ln > 1 && i < ln-1 { - o.R.VehicleTokenSyntheticDevices[i] = o.R.VehicleTokenSyntheticDevices[ln-1] - } - o.R.VehicleTokenSyntheticDevices = o.R.VehicleTokenSyntheticDevices[:ln-1] - break - } - } + related.R.VehicleToken = nil return nil } From 7ce5b598fed4d90fda9edca54c0961c50001ab77 Mon Sep 17 00:00:00 2001 From: Dylan Moreland <79415431+elffjs@users.noreply.github.com> Date: Tue, 25 Jul 2023 14:51:25 -0400 Subject: [PATCH 07/11] Check err --- internal/controllers/user_devices_controller.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/controllers/user_devices_controller.go b/internal/controllers/user_devices_controller.go index b9adcde90..553219b71 100644 --- a/internal/controllers/user_devices_controller.go +++ b/internal/controllers/user_devices_controller.go @@ -1968,7 +1968,9 @@ func (udc *UserDevicesController) PostMintDevice(c *fiber.Ctx) error { WalletAddress: addr, } - sd.Insert(c.Context(), udc.DBS().Writer, boil.Infer()) + if err:= sd.Insert(c.Context(), udc.DBS().Writer, boil.Infer()); err != nil { + return err + } return client.MintVehicleAndSDign(requestID, contracts.MintVehicleAndSdInput{ ManufacturerNode: makeTokenID, From c6d2677ca0b78fda024f57d2919557a27b76cbc3 Mon Sep 17 00:00:00 2001 From: Dylan Moreland Date: Tue, 25 Jul 2023 20:44:44 -0400 Subject: [PATCH 08/11] Remove some inapplicable tests --- cmd/devices-api/dependency_injection.go | 2 +- internal/services/registry/storage.go | 143 ++---------- internal/services/registry/storage_test.go | 246 +-------------------- 3 files changed, 24 insertions(+), 367 deletions(-) diff --git a/cmd/devices-api/dependency_injection.go b/cmd/devices-api/dependency_injection.go index f6567e48b..9b1a7ddc2 100644 --- a/cmd/devices-api/dependency_injection.go +++ b/cmd/devices-api/dependency_injection.go @@ -84,7 +84,7 @@ func (dc *dependencyContainer) getS3NFTServiceClient(ctx context.Context) *s3.Cl if dc.s3NFTServiceClient == nil { cfg, err := awsconfig.LoadDefaultConfig(ctx, - // awsconfig.WithRegion(dc.settings.AWSRegion), + awsconfig.WithRegion(dc.settings.AWSRegion), // Comment the below out if not using localhost awsconfig.WithEndpointResolverWithOptions(aws.EndpointResolverWithOptionsFunc( func(service, region string, options ...any) (aws.Endpoint, error) { diff --git a/internal/services/registry/storage.go b/internal/services/registry/storage.go index c57bdeff9..f2a3fac70 100644 --- a/internal/services/registry/storage.go +++ b/internal/services/registry/storage.go @@ -2,15 +2,10 @@ package registry import ( "context" - "database/sql" - "encoding/json" "errors" - "strconv" "github.com/DIMO-Network/devices-api/internal/config" - "github.com/DIMO-Network/devices-api/internal/constants" "github.com/DIMO-Network/devices-api/internal/contracts" - "github.com/DIMO-Network/devices-api/internal/services" "github.com/DIMO-Network/devices-api/internal/services/autopi" "github.com/DIMO-Network/devices-api/models" "github.com/DIMO-Network/shared/db" @@ -29,14 +24,11 @@ type StatusProcessor interface { } type proc struct { - ABI *abi.ABI - DB func() *db.ReaderWriter - Logger *zerolog.Logger - ap *autopi.Integration - settings *config.Settings - smartcarTaskSvc services.SmartcarTaskService - teslaTaskSvc services.TeslaTaskService - deviceDefSvc services.DeviceDefinitionService + ABI *abi.ABI + DB func() *db.ReaderWriter + Logger *zerolog.Logger + ap *autopi.Integration + settings *config.Settings } var errInvalidOEM = errors.New("unrecognized oem for synthetic device mint request") @@ -57,8 +49,8 @@ func (p *proc) Handle(ctx context.Context, data *ceData) error { qm.Load(models.MetaTransactionRequestRels.ClaimMetaTransactionRequestAftermarketDevice), qm.Load(models.MetaTransactionRequestRels.PairRequestAftermarketDevice), qm.Load(models.MetaTransactionRequestRels.UnpairRequestAftermarketDevice), - qm.Load(qm.Rels(models.MetaTransactionRequestRels.MintRequestSyntheticDevice, models.SyntheticDeviceRels.VehicleToken)), - qm.Load(qm.Rels(models.MetaTransactionRequestRels.BurnRequestSyntheticDevice, models.SyntheticDeviceRels.VehicleToken)), + qm.Load(models.MetaTransactionRequestRels.MintRequestSyntheticDevice), + qm.Load(models.MetaTransactionRequestRels.BurnRequestSyntheticDevice), ).One(context.Background(), p.DB().Reader) if err != nil { return err @@ -194,71 +186,9 @@ func (p *proc) Handle(ctx context.Context, data *ceData) error { if _, err := sd.Update(ctx, p.DB().Writer, boil.Infer()); err != nil { return err } - - intToken, intTkErr := sd.IntegrationTokenID.Uint64() - if !intTkErr { - return errors.New("error occurred parsing integration tokenID") - } - integration, err := p.deviceDefSvc.GetIntegrationByTokenID(ctx, intToken) - if err != nil { - return err - } - - ud, err := models.UserDeviceAPIIntegrations( - models.UserDeviceAPIIntegrationWhere.UserDeviceID.EQ(sd.R.VehicleToken.UserDeviceID.String), - models.UserDeviceAPIIntegrationWhere.Status.EQ(models.UserDeviceAPIIntegrationStatusPending), - models.UserDeviceAPIIntegrationWhere.IntegrationID.EQ(integration.Id), - qm.Load(models.UserDeviceAPIIntegrationRels.UserDevice), - ).One(ctx, p.DB().Reader) - if err != nil { - if errors.Is(err, sql.ErrNoRows) { - p.Logger.Debug().Err(err).Str("userDeviceID", sd.R.VehicleToken.UserDeviceID.String).Msg("Device has been deleted") - return nil - } - return err - } - - ud.Status = models.UserDeviceAPIIntegrationStatusPendingFirstData - if _, err := ud.Update(ctx, p.DB().Writer, boil.Infer()); err != nil { - return err - } - - switch integration.Vendor { - case constants.SmartCarVendor: - if err := p.smartcarTaskSvc.StartPoll(ud); err != nil { - logger.Err(err).Msg("Couldn't start Smartcar polling.") - return err - } - case constants.TeslaVendor: - extID, err := strconv.Atoi(ud.ExternalID.String) - if err != nil { - logger.Err(err).Msg("cannot convert tesla external id to int") - return err - } - - var metadata services.UserDeviceAPIIntegrationsMetadata - err = json.Unmarshal(ud.Metadata.JSON, &metadata) - if err != nil { - logger.Err(err).Msg("unable to parse metadata") - return err - } - - v := &services.TeslaVehicle{ - ID: extID, - VIN: ud.R.UserDevice.VinIdentifier.String, - VehicleID: metadata.TeslaVehicleID, - } - - if err := p.teslaTaskSvc.StartPoll(v, ud); err != nil { - logger.Err(err).Msg("Couldn't start Tesla polling.") - return err - } - default: - logger.Err(err).Msg("unable to complete request") - return errInvalidOEM - } } } + // It's very important that this be after the case for VehicleNodeMinted. case mtr.R.BurnRequestSyntheticDevice != nil: for _, l1 := range data.Transaction.Logs { if l1.Topics[0] == sdBurnEvent.ID { @@ -268,45 +198,8 @@ func (p *proc) Handle(ctx context.Context, data *ceData) error { return err } - sd := mtr.R.MintRequestSyntheticDevice - v := sd.R.VehicleToken - - if v.UserDeviceID.Valid { - intToken, _ := sd.IntegrationTokenID.Uint64() - integration, err := p.deviceDefSvc.GetIntegrationByTokenID(ctx, intToken) - if err != nil { - return err - } - - udai, err := models.FindUserDeviceAPIIntegration(ctx, p.DB().Reader, v.UserDeviceID.String, integration.Id) - if err != nil { - if err == sql.ErrNoRows { - return nil - } - return err - } - - // In these two states, the job has already stopped, or never started. - if udai.Status != models.UserDeviceAPIIntegrationStatusAuthenticationFailure && udai.Status != models.UserDeviceAPIIntegrationStatusFailed { - switch integration.Vendor { - case constants.SmartCarVendor: - if err := p.smartcarTaskSvc.StopPoll(udai); err != nil { - return err - } - case constants.TeslaVendor: - if err := p.teslaTaskSvc.StopPoll(udai); err != nil { - return err - } - } - - if _, err := udai.Delete(ctx, p.DB().Writer); err != nil { - return err - } - } - - if _, err := sd.Delete(ctx, p.DB().Writer); err != nil { - return err - } + if _, err := mtr.R.MintRequestSyntheticDevice.Delete(ctx, p.DB().Writer); err != nil { + return err } } } @@ -337,9 +230,6 @@ func NewProcessor( logger *zerolog.Logger, ap *autopi.Integration, settings *config.Settings, - smartcarTaskSvc services.SmartcarTaskService, - teslaTaskService services.TeslaTaskService, - deviceDefSvc services.DeviceDefinitionService, ) (StatusProcessor, error) { abi, err := contracts.RegistryMetaData.GetAbi() if err != nil { @@ -347,13 +237,10 @@ func NewProcessor( } return &proc{ - ABI: abi, - DB: db, - Logger: logger, - ap: ap, - settings: settings, - smartcarTaskSvc: smartcarTaskSvc, - teslaTaskSvc: teslaTaskService, - deviceDefSvc: deviceDefSvc, + ABI: abi, + DB: db, + Logger: logger, + ap: ap, + settings: settings, }, nil } diff --git a/internal/services/registry/storage_test.go b/internal/services/registry/storage_test.go index 725c12e37..2d1319912 100644 --- a/internal/services/registry/storage_test.go +++ b/internal/services/registry/storage_test.go @@ -2,19 +2,15 @@ package registry import ( "context" - "encoding/json" "fmt" "math/big" "testing" "time" - ddgrpc "github.com/DIMO-Network/device-definitions-api/pkg/grpc" "github.com/rs/zerolog" "github.com/DIMO-Network/devices-api/internal/config" - "github.com/DIMO-Network/devices-api/internal/constants" "github.com/DIMO-Network/devices-api/internal/contracts" - "github.com/DIMO-Network/devices-api/internal/services" mock_services "github.com/DIMO-Network/devices-api/internal/services/mocks" "github.com/DIMO-Network/devices-api/internal/test" "github.com/DIMO-Network/devices-api/models" @@ -56,7 +52,7 @@ func (s *StorageTestSuite) SetupSuite() { s.deviceDefSvc = mock_services.NewMockDeviceDefinitionService(s.mockCtrl) s.scTaskSvc = mock_services.NewMockSmartcarTaskService(s.mockCtrl) s.teslaTaskService = mock_services.NewMockTeslaTaskService(s.mockCtrl) - proc, err := NewProcessor(s.dbs.DBS, logger, nil, &config.Settings{Environment: "prod"}, s.scTaskSvc, s.teslaTaskService, s.deviceDefSvc) + proc, err := NewProcessor(s.dbs.DBS, logger, nil, &config.Settings{Environment: "prod"}) if err != nil { s.T().Fatal(err) } @@ -82,7 +78,7 @@ func TestStorageTestSuite(t *testing.T) { suite.Run(t, new(StorageTestSuite)) } -func (s *StorageTestSuite) Test_SmartCar_StartPollOnMint() { +func (s *StorageTestSuite) Test_SyntheticMintSetsID() { vehicleID := int64(54) integrationNode := int64(1) childKeyNumber := 300 @@ -91,14 +87,6 @@ func (s *StorageTestSuite) Test_SmartCar_StartPollOnMint() { ownerAddr := common.HexToAddress("1000") integrationID := ksuid.New().String() - udArgs := &models.UserDeviceAPIIntegration{} - s.scTaskSvc.EXPECT().StartPoll(gomock.AssignableToTypeOf(udArgs)).DoAndReturn( - func(udai *models.UserDeviceAPIIntegration) error { - udArgs = udai - return nil - }, - ) - ud := models.UserDevice{ ID: ksuid.New().String(), } @@ -149,12 +137,6 @@ func (s *StorageTestSuite) Test_SmartCar_StartPollOnMint() { } s.MustInsert(&udi) - integration := &ddgrpc.Integration{Id: integrationID, Vendor: constants.SmartCarVendor} - var intTokenID uint64 - s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), gomock.Any()).Return(integration, nil).Do(func(ct context.Context, arg uint64) { - intTokenID = arg - }) - a, _ := contracts.RegistryMetaData.GetAbi() err = s.proc.Handle(context.TODO(), &ceData{ @@ -186,231 +168,17 @@ func (s *StorageTestSuite) Test_SmartCar_StartPollOnMint() { ).One(s.ctx, s.dbs.DBS().Reader) s.NoError(err) - s.Equal(udi.UserDeviceID, udArgs.UserDeviceID) - s.Equal(uint64(integrationNode), intTokenID) - - tkID := types.NewNullDecimal(decimal.New(30, 0)) - s.Equal(tkID, sd.TokenID) -} - -func (s *StorageTestSuite) Test_Tesla_StartPollOnMint() { - vehicleID := int64(55) - integrationNode := int64(2) - childKeyNumber := 400 - syntheticDeviceAddr := common.HexToAddress("5") - cipher := new(shared.ROT13Cipher) - ownerAddr := common.HexToAddress("13") - integrationID := ksuid.New().String() - integration := &ddgrpc.Integration{Id: integrationID, Vendor: constants.TeslaVendor} - - ud := models.UserDevice{ - ID: ksuid.New().String(), - VinIdentifier: null.StringFrom("5YJYGDEE9MF073630"), - } - s.MustInsert(&ud) - - mtx := models.MetaTransactionRequest{ - ID: ksuid.New().String(), - Status: models.MetaTransactionRequestStatusMined, - } - s.MustInsert(&mtx) - - vnft := models.VehicleNFT{ - MintRequestID: mtx.ID, - UserDeviceID: null.StringFrom(ud.ID), - TokenID: types.NewNullDecimal(decimal.New(vehicleID, 0)), - OwnerAddress: null.BytesFrom(ownerAddr.Bytes()), - } - s.MustInsert(&vnft) - - syntMtx := models.MetaTransactionRequest{ - ID: ksuid.New().String(), - Status: models.MetaTransactionRequestStatusMined, - } - s.MustInsert(&syntMtx) - - vnID := types.NewNullDecimal(decimal.New(vehicleID, 0)) - syntheticDevice := models.SyntheticDevice{ - VehicleTokenID: vnID, - IntegrationTokenID: types.NewDecimal(decimal.New(integrationNode, 0)), - WalletChildNumber: childKeyNumber, - WalletAddress: syntheticDeviceAddr.Bytes(), - MintRequestID: syntMtx.ID, - } - s.MustInsert(&syntheticDevice) - - extID, err := cipher.Encrypt("1493095587059755") - s.NoError(err) - refToken, err := cipher.Encrypt("eyJhbGciOiJSUzI1NiIsInR5cCI") - s.NoError(err) - - meta := services.UserDeviceAPIIntegrationsMetadata{ - Commands: &services.UserDeviceAPIIntegrationsMetadataCommands{ - Enabled: []string{"doors/unlock", "doors/lock", "trunk/open", "frunk/open", "charge/limit"}, - }, - TeslaVehicleID: 163418800938, - } - - mb, err := json.Marshal(meta) - s.NoError(err) - - udi := models.UserDeviceAPIIntegration{ - IntegrationID: integration.Id, - UserDeviceID: ud.ID, - Status: models.UserDeviceAPIIntegrationStatusPending, - ExternalID: null.StringFrom(extID), - AccessExpiresAt: null.TimeFrom(time.Now()), - RefreshToken: null.StringFrom(refToken), - Metadata: null.JSONFrom(mb), - } - s.MustInsert(&udi) - - a, err := contracts.RegistryMetaData.GetAbi() - s.NoError(err) - - var intTokenID uint64 - s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), gomock.Any()).Return(integration, nil).Do(func(ct context.Context, arg uint64) { - intTokenID = arg - }) - - udArgs := &models.UserDeviceAPIIntegration{} - s.teslaTaskService.EXPECT().StartPoll(gomock.Any(), gomock.Any()).Return(nil).Do(func(teslaVehicle *services.TeslaVehicle, arg *models.UserDeviceAPIIntegration) { - udArgs = arg - }) - - err = s.proc.Handle(context.TODO(), &ceData{ - RequestID: syntMtx.ID, - Type: "Confirmed", - Transaction: ceTx{ - Hash: "0x28db529e841dc0bc46c27a5a43ae7db8ed43294c1b97a8b81b142b8fd6763f43", - Logs: []ceLog{ - { - Topics: []common.Hash{ - a.Events["SyntheticDeviceNodeMinted"].ID, - common.BigToHash(big.NewInt(vehicleID)), - syntheticDeviceAddr.Hash(), - ownerAddr.Hash(), - }, - Data: common.FromHex( - "0000000000000000000000000000000000000000000000000000000000000001" + - "000000000000000000000000000000000000000000000000000000000000001e", - ), - }, - }, - }, - }) - s.NoError(err) - - sd, err := models.SyntheticDevices( - models.SyntheticDeviceWhere.MintRequestID.EQ(syntMtx.ID), - qm.Load(models.SyntheticDeviceRels.VehicleToken), - ).One(s.ctx, s.dbs.DBS().Reader) - s.NoError(err) - - s.Equal(udi.UserDeviceID, udArgs.UserDeviceID) - s.Equal(uint64(integrationNode), intTokenID) - tkID := types.NewNullDecimal(decimal.New(30, 0)) s.Equal(tkID, sd.TokenID) } -func (s *StorageTestSuite) Test_InvalidOEMInMetaTx() { - vehicleID := int64(54) - integrationNode := int64(1) - childKeyNumber := 300 - syntheticDeviceAddr := common.HexToAddress("4") - cipher := new(shared.ROT13Cipher) - ownerAddr := common.HexToAddress("1000") - integrationID := ksuid.New().String() - - ud := models.UserDevice{ - ID: ksuid.New().String(), - } - s.MustInsert(&ud) - - mtr := models.MetaTransactionRequest{ - ID: ksuid.New().String(), - Status: models.MetaTransactionRequestStatusMined, - } - s.MustInsert(&mtr) - - vnft := models.VehicleNFT{ - MintRequestID: mtr.ID, - UserDeviceID: null.StringFrom(ud.ID), - TokenID: types.NewNullDecimal(decimal.New(vehicleID, 0)), - OwnerAddress: null.BytesFrom(ownerAddr.Bytes()), - } - s.MustInsert(&vnft) - - syntMtr := models.MetaTransactionRequest{ - ID: ksuid.New().String(), - Status: models.MetaTransactionRequestStatusMined, - } - s.MustInsert(&syntMtr) - - vnID := types.NewNullDecimal(decimal.New(vehicleID, 0)) - syntheticDevice := models.SyntheticDevice{ - VehicleTokenID: vnID, - IntegrationTokenID: types.NewDecimal(decimal.New(integrationNode, 0)), - WalletChildNumber: childKeyNumber, - WalletAddress: syntheticDeviceAddr.Bytes(), - MintRequestID: syntMtr.ID, - } - s.MustInsert(&syntheticDevice) - - acToken, err := cipher.Encrypt("mockAccessToken") - s.NoError(err) - refToken, err := cipher.Encrypt("mockRefreshToken") - s.NoError(err) - - udi := models.UserDeviceAPIIntegration{ - IntegrationID: integrationID, - UserDeviceID: ud.ID, - Status: models.UserDeviceAPIIntegrationStatusPending, - AccessToken: null.StringFrom(acToken), - AccessExpiresAt: null.TimeFrom(time.Now()), - RefreshToken: null.StringFrom(refToken), - } - s.MustInsert(&udi) - - integration := &ddgrpc.Integration{Id: integrationID, Vendor: "genericInvalidOEMName"} - s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), gomock.Any()).Return(integration, nil).Do(func(ct context.Context, arg uint64) { - }) - - a, _ := contracts.RegistryMetaData.GetAbi() - - err = s.proc.Handle(context.TODO(), &ceData{ - RequestID: syntMtr.ID, - Type: "Confirmed", - Transaction: ceTx{ - Hash: "0x28db529e841dc0bc46c27a5a43ae7db8ed43294c1b97a8b81b142b8fd6763f43", - Logs: []ceLog{ - { - Topics: []common.Hash{ - a.Events["SyntheticDeviceNodeMinted"].ID, - common.BigToHash(big.NewInt(vehicleID)), - syntheticDeviceAddr.Hash(), - ownerAddr.Hash(), - }, - Data: common.FromHex( - "0000000000000000000000000000000000000000000000000000000000000001" + - "000000000000000000000000000000000000000000000000000000000000001e", - ), - }, - }, - }, - }) - s.T().Log(err, errInvalidOEM) - s.Require().Equal(err.Error(), errInvalidOEM.Error()) -} - func (s *StorageTestSuite) TestMintVehicle() { ctx := context.TODO() logger := zerolog.Nop() s.mockCtrl = gomock.NewController(s.T()) - proc, err := NewProcessor(s.dbs.DBS, &logger, nil, &config.Settings{Environment: "prod"}, s.scTaskSvc, s.teslaTaskService, s.deviceDefSvc) + proc, err := NewProcessor(s.dbs.DBS, &logger, nil, &config.Settings{Environment: "prod"}) s.Require().NoError(err) ud := models.UserDevice{ @@ -456,8 +224,10 @@ func (s *StorageTestSuite) TestMintVehicle() { s.Equal(common.HexToAddress("7e74d0f663d58d12817b8bef762bcde3af1f63d6"), common.BytesToAddress(vnft.OwnerAddress.Bytes)) } -func (s *StorageTestSuite) MustInsert(o interface { - Insert(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) error -}) { +func (s *StorageTestSuite) MustInsert(o boilInsertable) { s.Require().NoError(o.Insert(context.TODO(), s.dbs.DBS().Writer, boil.Infer())) } + +type boilInsertable interface { + Insert(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) error +} From 44498b1ffe08377792b08f3991957e782664b624 Mon Sep 17 00:00:00 2001 From: Dylan Moreland Date: Tue, 25 Jul 2023 20:44:59 -0400 Subject: [PATCH 09/11] Don't need this error --- internal/services/registry/storage.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/internal/services/registry/storage.go b/internal/services/registry/storage.go index f2a3fac70..124f861f9 100644 --- a/internal/services/registry/storage.go +++ b/internal/services/registry/storage.go @@ -2,7 +2,6 @@ package registry import ( "context" - "errors" "github.com/DIMO-Network/devices-api/internal/config" "github.com/DIMO-Network/devices-api/internal/contracts" @@ -31,8 +30,6 @@ type proc struct { settings *config.Settings } -var errInvalidOEM = errors.New("unrecognized oem for synthetic device mint request") - func (p *proc) Handle(ctx context.Context, data *ceData) error { logger := p.Logger.With(). Str("requestId", data.RequestID). From 6d8124cc6f48687c4c2a8921f61ec95051bd76b8 Mon Sep 17 00:00:00 2001 From: Dylan Moreland Date: Tue, 25 Jul 2023 22:12:12 -0400 Subject: [PATCH 10/11] All tests are go --- cmd/devices-api/api.go | 2 +- go.sum | 101 --- .../synthetic_devices_controller.go | 21 + .../synthetic_devices_controller_test.go | 763 ++++++++---------- internal/test/helpers.go | 6 +- 5 files changed, 369 insertions(+), 524 deletions(-) diff --git a/cmd/devices-api/api.go b/cmd/devices-api/api.go index d3a2154b4..e8494d036 100644 --- a/cmd/devices-api/api.go +++ b/cmd/devices-api/api.go @@ -343,7 +343,7 @@ func startWebAPI(logger zerolog.Logger, settings *config.Settings, pdb db.Store, logger.Fatal().Err(err).Msg("Failed to create vin credentialer listener") } - store, err := registry.NewProcessor(pdb.DBS, &logger, autoPi, settings, scTaskSvc, teslaTaskService, ddSvc) + store, err := registry.NewProcessor(pdb.DBS, &logger, autoPi, settings) if err != nil { logger.Fatal().Err(err).Msg("Failed to create registry storage client") } diff --git a/go.sum b/go.sum index fc41c9de9..855571736 100644 --- a/go.sum +++ b/go.sum @@ -54,7 +54,6 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0/go.mod h1:+6sju8gk8FRmSajX3Oz4G5Gm7P+mbqE9FVaXXFYTkCM= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= @@ -65,8 +64,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM= github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/DIMO-Network/device-data-api v0.4.18 h1:UF7d2uzSLLkKIAUqhXf2TDHrm6gRUfmjJfGiGVa1bec= -github.com/DIMO-Network/device-data-api v0.4.18/go.mod h1:kVJwYVg1ThTY3DA2AFLz2hIMK9yOpxV2BgZ4Wd7qMxg= github.com/DIMO-Network/device-data-api v0.4.23-0.20230718210255-60a2c7be0aa7 h1:E+/o2SQ7An3ZPxbr2lMgv0MjKrk+q//PME2SUaB2hlM= github.com/DIMO-Network/device-data-api v0.4.23-0.20230718210255-60a2c7be0aa7/go.mod h1:kVJwYVg1ThTY3DA2AFLz2hIMK9yOpxV2BgZ4Wd7qMxg= github.com/DIMO-Network/device-definitions-api v1.0.7 h1:20IdqrAdPJ9YtBksgGR/edDe4K6eXBtXrEnSRs/hocQ= @@ -93,7 +90,6 @@ github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4Oe github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/Microsoft/hcsshim v0.9.7 h1:mKNHW/Xvv1aFH87Jb6ERDzXTJTLPlmzfZ28VBFD/bfg= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= @@ -135,75 +131,40 @@ github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevB github.com/avast/retry-go/v4 v4.3.3 h1:G56Bp6mU0b5HE1SkaoVjscZjlQb0oy4mezwY/cGH19w= github.com/avast/retry-go/v4 v4.3.3/go.mod h1:rg6XFaiuFYII0Xu3RDbZQkxCofFwruZKW8oEF1jpWiU= github.com/aws/aws-sdk-go v1.43.45 h1:2708Bj4uV+ym62MOtBnErm/CDX61C4mFe9V2gXy1caE= -github.com/aws/aws-sdk-go-v2 v1.17.6/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2 v1.17.8 h1:GMupCNNI7FARX27L7GjCJM8NgivWbRgpjNI/hOQjFS8= -github.com/aws/aws-sdk-go-v2 v1.17.8/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2 v1.19.0 h1:klAT+y3pGFBU/qVf1uzwttpBbiuozJYWzNLHioyDJ+k= github.com/aws/aws-sdk-go-v2 v1.19.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno= -github.com/aws/aws-sdk-go-v2/config v1.18.21 h1:ENTXWKwE8b9YXgQCsruGLhvA9bhg+RqAsL9XEMEsa2c= -github.com/aws/aws-sdk-go-v2/config v1.18.21/go.mod h1:+jPQiVPz1diRnjj6VGqWcLK6EzNmQ42l7J3OqGTLsSY= github.com/aws/aws-sdk-go-v2/config v1.18.28 h1:TINEaKyh1Td64tqFvn09iYpKiWjmHYrG1fa91q2gnqw= github.com/aws/aws-sdk-go-v2/config v1.18.28/go.mod h1:nIL+4/8JdAuNHEjn/gPEXqtnS02Q3NXB/9Z7o5xE4+A= -github.com/aws/aws-sdk-go-v2/credentials v1.13.20 h1:oZCEFcrMppP/CNiS8myzv9JgOzq2s0d3v3MXYil/mxQ= -github.com/aws/aws-sdk-go-v2/credentials v1.13.20/go.mod h1:xtZnXErtbZ8YGXC3+8WfajpMBn5Ga/3ojZdxHq6iI8o= github.com/aws/aws-sdk-go-v2/credentials v1.13.27 h1:dz0yr/yR1jweAnsCx+BmjerUILVPQ6FS5AwF/OyG1kA= github.com/aws/aws-sdk-go-v2/credentials v1.13.27/go.mod h1:syOqAek45ZXZp29HlnRS/BNgMIW6uiRmeuQsz4Qh2UE= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.2 h1:jOzQAesnBFDmz93feqKnsTHsXrlwWORNZMFHMV+WLFU= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.2/go.mod h1:cDh1p6XkSGSwSRIArWRc6+UqAQ7x4alQ0QfpVR6f+co= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5 h1:kP3Me6Fy3vdi+9uHd7YLr6ewPxRL+PU6y15urfTaamU= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.5/go.mod h1:Gj7tm95r+QsDoN2Fhuz/3npQvcZbkEf5mL70n3Xfluc= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30/go.mod h1:LUBAO3zNXQjoONBKn/kR1y0Q4cj/D02Ts0uHYjcCQLM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32 h1:dpbVNUjczQ8Ae3QKHbpHBpfvaVkRdesxpTOe9pTouhU= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32/go.mod h1:RudqOgadTWdcS3t/erPQo24pcVEoYyqj/kKW5Vya21I= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35 h1:hMUCiE3Zi5AHrRNGf5j985u0WyqI6r2NULhUfo0N/No= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.35/go.mod h1:ipR5PvpSPqIqL5Mi82BxLnfMkHVbmco8kUwO2xrCi0M= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24/go.mod h1:gAuCezX/gob6BSMbItsSlMb6WZGV7K2+fWOvk8xBSto= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26 h1:QH2kOS3Ht7x+u0gHCh06CXL/h6G8LQJFpZfFBYBNboo= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26/go.mod h1:vq86l7956VgFr0/FWQ2BWnK07QC3WYsepKzy33qqY5U= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29 h1:yOpYx+FTBdpk/g+sBU6Cb1H0U/TLEcYYp66mYqsPpcc= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.29/go.mod h1:M/eUABlDbw2uVrdAn+UsI6M727qp2fxkp8K0ejcBDUY= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.33 h1:HbH1VjUgrCdLJ+4lnnuLI4iVNRvBbBELGaJ5f69ClA8= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.33/go.mod h1:zG2FcwjQarWaqXSCGpgcr3RSjZ6dHGguZSppUL0XR7Q= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36 h1:8r5m1BoAWkn0TDC34lUculryf7nUF25EgIMdjvGCkgo= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.36/go.mod h1:Rmw2M1hMVTwiUhjwMoIBFWFJMhvJbct06sSidxInkhY= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.24 h1:zsg+5ouVLLbePknVZlUMm1ptwyQLkjjLMWnN+kVs5dA= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.24/go.mod h1:+fFaIjycTmpV6hjmPTbyU9Kp5MI/lA+bbibcAtmlhYA= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.27 h1:cZG7psLfqpkB6H+fIrgUDWmlzM474St1LP0jcz272yI= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.27/go.mod h1:ZdjYvJpDlefgh8/hWelJhqgqJeodxu4SmbVsSdBlL7E= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.27 h1:qIw7Hg5eJEc1uSxg3hRwAthPAO7NeOd4dPxhaTi0yB0= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.27/go.mod h1:Zz0kvhcSlu3NX4XJkaGgdjaa+u7a9LYuy8JKxA5v3RM= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.30 h1:Bje8Xkh2OWpjBdNfXLrnn8eZg569dUQmhgtydxAYyP0= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.30/go.mod h1:qQtIBl5OVMfmeQkz8HaVyh5DzFmmFXyvK27UgIgOr4c= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.26 h1:uUt4XctZLhl9wBE1L8lobU3bVN8SNUP7T+olb0bWBO4= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.26/go.mod h1:Bd4C/4PkVGubtNe5iMXu5BNnaBi/9t/UsFspPt4ram8= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29 h1:IiDolu/eLmuB18DRZibj77n1hHQT7z12jnGO7Ze3pLc= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.29/go.mod h1:fDbkK4o7fpPXWn8YAPmTieAMuB9mk/VgvW64uaUqxd4= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.1 h1:lRWp3bNu5wy0X3a8GS42JvZFlv++AKsMdzEnoiVJrkg= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.1/go.mod h1:VXBHSxdN46bsJrkniN68psSwbyBKsazQfU2yX/iSDso= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.4 h1:hx4WksB0NRQ9utR+2c3gEGzl6uKj3eM6PMQ6tN3lgXs= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.4/go.mod h1:JniVpqvw90sVjNqanGLufrVapWySL28fhBlYgl96Q/w= -github.com/aws/aws-sdk-go-v2/service/kms v1.20.7 h1:7Ligq/4Mei9qZScT1p51REuqq0dB8MLOIs8X/tsLfB0= -github.com/aws/aws-sdk-go-v2/service/kms v1.20.7/go.mod h1:1OnRDyIEZ/RFBhxzu9oFZ3zV0RU0I9GWT3Dxz3pgITU= github.com/aws/aws-sdk-go-v2/service/kms v1.23.1 h1:u9A03kEyjBCt44Tg3NMtWJL2SnIvMpipDIoQYtXYzMA= github.com/aws/aws-sdk-go-v2/service/kms v1.23.1/go.mod h1:BuDl6WtqaDJbd9c29q/EFHrZjuWlrJN7oMNy5Yd5n7Q= -github.com/aws/aws-sdk-go-v2/service/s3 v1.31.3 h1:MG+2UlhyBL3oCOoHbUQh+Sqr3elN0I5PBe0MtVh0xMg= -github.com/aws/aws-sdk-go-v2/service/s3 v1.31.3/go.mod h1:aSl9/LJltSz1cVusiR/Mu8tvI4Sv/5w/WWrJmmkNii0= github.com/aws/aws-sdk-go-v2/service/s3 v1.37.0 h1:PalLOEGZ/4XfQxpGZFTLaoJSmPoybnqJYotaIZEf/Rg= github.com/aws/aws-sdk-go-v2/service/s3 v1.37.0/go.mod h1:PwyKKVL0cNkC37QwLcrhyeCrAk+5bY8O2ou7USyAS2A= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.8 h1:5cb3D6xb006bPTqEfCNaEA6PPEfBXxxy4NNeX/44kGk= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.8/go.mod h1:GNIveDnP+aE3jujyUSH5aZ/rktsTM5EvtKnCqBZawdw= github.com/aws/aws-sdk-go-v2/service/sso v1.12.13 h1:sWDv7cMITPcZ21QdreULwxOOAmE05JjEsT6fCDtDA9k= github.com/aws/aws-sdk-go-v2/service/sso v1.12.13/go.mod h1:DfX0sWuT46KpcqbMhJ9QWtxAIP1VozkDWf8VAkByjYY= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.8 h1:NZaj0ngZMzsubWZbrEFSB4rgSQRbFq38Sd6KBxHuOIU= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.8/go.mod h1:44qFP1g7pfd+U+sQHLPalAPKnyfTZjJsYR4xIwsJy5o= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13 h1:BFubHS/xN5bjl818QaroN6mQdjneYQ+AOx44KNXlyH4= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.13/go.mod h1:BzqsVVFduubEmzrVtUFQQIQdFqvUItF8XUq2EnS8Wog= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.9 h1:Qf1aWwnsNkyAoqDqmdM3nHwN78XQjec27LjM6b9vyfI= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.9/go.mod h1:yyW88BEPXA2fGFyI2KCcZC3dNpiT0CZAHaF+i656/tQ= github.com/aws/aws-sdk-go-v2/service/sts v1.19.3 h1:e5mnydVdCVWxP+5rPAGi2PYxC7u2OZgH1ypC114H04U= github.com/aws/aws-sdk-go-v2/service/sts v1.19.3/go.mod h1:yVGZA1CPkmUhBdA039jXNJJG7/6t+G+EBWmFq23xqnY= github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= @@ -214,7 +175,6 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bsm/redislock v0.7.2 h1:jggqOio8JyX9FJBKIfjF3fTxAu/v7zC5mAID9LveqG4= github.com/bsm/redislock v0.7.2/go.mod h1:kS2g0Yvlymc9Dz8V3iVYAtLAaSVruYbAFdYBDrmC5WU= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= @@ -277,25 +237,10 @@ github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5b github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= -github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= -github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= -github.com/containerd/cgroups v1.0.4/go.mod h1:nLNQtsF7Sl2HxNebu77i1R0oDlhiTG+kO4JTrUzo6IA= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/containerd v1.6.19 h1:F0qgQPrG0P2JPgwpxWxYavrVeXAG0ezUIB9Z/4FTUAU= github.com/containerd/containerd v1.6.19/go.mod h1:HZCDMn4v/Xl2579/MvtOC2M206i+JJ6VxFWU/NetrGY= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= -github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= -github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= -github.com/containerd/go-cni v1.1.6/go.mod h1:BWtoWl5ghVymxu6MBjg79W9NZrCRyHIdUtk4cauMe34= -github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= -github.com/containerd/imgcrypt v1.1.4/go.mod h1:LorQnPtzL/T0IyCeftcsMEO7AqxUDbdO8j/tSUpgxvo= -github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= -github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ= -github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= -github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= -github.com/containernetworking/cni v1.1.1/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= -github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19sZPp3ry5uHSkI4LPxV8= -github.com/containers/ocicrypt v1.1.3/go.mod h1:xpdkbVAuaH3WzbEabUd5yDsl9SwJA5pABH85425Es2g= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -324,15 +269,12 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE= github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v23.0.1+incompatible h1:vjgvJZxprTTE1A37nm+CLNAdwu6xZekyoiVlUZEINcY= github.com/docker/docker v23.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= -github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -352,7 +294,6 @@ github.com/elastic/elastic-transport-go/v8 v8.1.0 h1:NeqEz1ty4RQz+TVbUrpSU7pZ48X github.com/elastic/elastic-transport-go/v8 v8.1.0/go.mod h1:87Tcz8IVNe6rVSLdBux1o/PEItLtyabHU3naC7IoqKI= github.com/elastic/go-elasticsearch/v8 v8.6.0 h1:xMaSe8jIh7NHzmNo9YBkewmaD2Pr+tX+zLkXxhieny4= github.com/elastic/go-elasticsearch/v8 v8.6.0/go.mod h1:Usvydt+x0dv9a1TzEUaovqbJor8rmOHy5dSmPeMAE2k= -github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -397,8 +338,6 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -442,7 +381,6 @@ github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc= github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -513,7 +451,6 @@ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8 github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -534,7 +471,6 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -612,7 +548,6 @@ github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ= github.com/iron-io/iron_go3 v0.0.0-20190916120531-a4a7f74b73ac h1:w5wltlINIIqRTqQ64dASrCo0fM7k9nosPbKCZnkL0W0= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jarcoal/httpmock v1.1.0 h1:F47ChZj1Y2zFsCXxNkBPwNNKnAyOATcdQibk0qEdVCE= @@ -721,10 +656,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfr github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= @@ -737,17 +670,11 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo= github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/sys/mount v0.3.3/go.mod h1:PBaEorSNTLG5t/+4EgukEQVlAvVEc6ZjTySwKdqp5K0= github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= -github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= -github.com/moby/sys/signal v0.6.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= -github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs= github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -800,7 +727,6 @@ github.com/opencontainers/runc v1.1.4 h1:nRCz/8sKg6K6jgYAFLDlXzPeITBZJyX28DBVhWD github.com/opencontainers/runc v1.1.4/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= -github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -886,7 +812,6 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4= github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8= github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4= @@ -921,7 +846,6 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= -github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -948,7 +872,6 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/testcontainers/testcontainers-go v0.19.0 h1:3bmFPuQRgVIQwxZJERyzB8AogmJW3Qzh8iDyfJbPhi8= github.com/testcontainers/testcontainers-go v0.19.0/go.mod h1:3YsSoxK0rGEUzbGD4gUVt1Nm3GJpCIq94GX+2LSf3d4= github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= @@ -968,7 +891,6 @@ github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hM github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= @@ -977,9 +899,7 @@ github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= @@ -1000,8 +920,6 @@ github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23n github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1010,13 +928,10 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= -go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU= go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= -go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -1024,13 +939,7 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0/go.mod h1:vEhqr0m4eTc+DWxfsXoXue2GBgV2uUwVznkGIHW/e5w= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDDKDkvI9dP/FIhpmna5lkqPUQdEjFAM8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0/go.mod h1:keUU7UfnwWTWpJ+FWnyqmogPa82nuU5VUANFq49hlMY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0/go.mod h1:QNX1aly8ehqqX1LEa6YniTU7VY9I6R3X/oPxhGdTceE= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/automaxprocs v1.5.1 h1:e1YG66Lrk73dn4qhg8WFSvhF0JuFQF0ERIp4rpuV8Qk= go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU= @@ -1606,11 +1515,9 @@ gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mN gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= gopkg.in/jcmturner/gokrb5.v7 v7.4.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/redis.v5 v5.2.9/go.mod h1:6gtv0/+A4iM08kdRfocWYB3bLX2tebpNtfKlFT6H4mY= -gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1636,13 +1543,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs= -k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U= -k8s.io/apiserver v0.22.5/go.mod h1:s2WbtgZAkTKt679sYtSudEQrTGWUSQAPe6MupLnlmaQ= -k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y= -k8s.io/component-base v0.22.5/go.mod h1:VK3I+TjuF9eaa+Ln67dKxhGar5ynVbwnGrUiNF4MqCI= -k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= @@ -1691,6 +1591,5 @@ modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/internal/controllers/synthetic_devices_controller.go b/internal/controllers/synthetic_devices_controller.go index 552602261..f27f54442 100644 --- a/internal/controllers/synthetic_devices_controller.go +++ b/internal/controllers/synthetic_devices_controller.go @@ -2,6 +2,7 @@ package controllers import ( "context" + "database/sql" "fmt" "math/big" @@ -104,6 +105,19 @@ func (sdc *SyntheticDevicesController) getEIP712Mint(integrationID, vehicleNode // @Success 200 {array} signer.TypedData // @Router /user/devices/{userDeviceID}/integrations/{integrationID}/commands/mint [get] func (sdc *SyntheticDevicesController) GetSyntheticDeviceMintingPayload(c *fiber.Ctx) error { + userID := helpers.GetUserID(c) + + user, err := sdc.usersClient.GetUser(c.Context(), &pb.GetUserRequest{Id: userID}) + if err != nil { + return helpers.GrpcErrorToFiber(err, "error occurred when fetching user") + } + + if user.EthereumAddress == nil { + return fiber.NewError(fiber.StatusUnauthorized, "User does not have an Ethereum address.") + } + + userAddr := common.HexToAddress(*user.EthereumAddress) + userDeviceID := c.Params("userDeviceID") integrationID := c.Params("integrationID") ud, err := models.UserDevices( @@ -112,6 +126,9 @@ func (sdc *SyntheticDevicesController) GetSyntheticDeviceMintingPayload(c *fiber qm.Load(models.UserDeviceRels.UserDeviceAPIIntegrations, models.UserDeviceAPIIntegrationWhere.IntegrationID.EQ(integrationID)), ).One(c.Context(), sdc.DBS().Reader) if err != nil { + if err == sql.ErrNoRows { + return fiber.NewError(fiber.StatusNotFound, "No vehicle with that id found.") + } return err } @@ -119,6 +136,10 @@ func (sdc *SyntheticDevicesController) GetSyntheticDeviceMintingPayload(c *fiber return fiber.NewError(fiber.StatusConflict, "Vehicle not minted.") } + if userAddr != common.BytesToAddress(ud.R.VehicleNFT.OwnerAddress.Bytes) { + return fiber.NewError(fiber.StatusUnauthorized, "User's address does not control this device.") + } + if ud.R.VehicleNFT.R.VehicleTokenSyntheticDevice != nil { return fiber.NewError(fiber.StatusConflict, "Vehicle already paired with a synthetic device.") } diff --git a/internal/controllers/synthetic_devices_controller_test.go b/internal/controllers/synthetic_devices_controller_test.go index 46e47aa06..0e1f68358 100644 --- a/internal/controllers/synthetic_devices_controller_test.go +++ b/internal/controllers/synthetic_devices_controller_test.go @@ -1,510 +1,435 @@ package controllers -// var signature = "0xa4438e5cb667dc63ebd694167ae3ad83585f2834c9b04895dd890f805c4c459a024ed9df1b03872536b4ac0c7720d02cb787884a093cfcde5c3bd7f94657e30c1b" -// var userEthAddress = "0xd64E249A06ee6263d989e43aBFe12748a2506f88" -// var mockProducer *smock.SyncProducer -// var mockUserID = ksuid.New().String() -// var mockSmartClientToken = &smartcar.Token{ -// Access: "mockAccessToken", -// AccessExpiry: time.Now().Add(time.Hour + 1), -// Refresh: "mockRefreshToken", -// } - -// type SyntheticDevicesControllerTestSuite struct { -// suite.Suite -// pdb db.Store -// container testcontainers.Container -// ctx context.Context -// mockCtrl *gomock.Controller -// app *fiber.App -// deviceDefSvc *mock_services.MockDeviceDefinitionService -// userClient *mock_services.MockUserServiceClient -// sdc SyntheticDevicesController -// syntheticDeviceSigSvc *mock_services.MockSyntheticWalletInstanceService -// smartcarClient *mock_services.MockSmartcarClient -// teslaService *mock_services.MockTeslaService -// } - -// // SetupSuite starts container db -// func (s *SyntheticDevicesControllerTestSuite) SetupSuite() { -// s.ctx = context.Background() -// s.pdb, s.container = test.StartContainerDatabase(s.ctx, s.T(), migrationsDirRelPath) -// } - -// func (s *SyntheticDevicesControllerTestSuite) SetupTest() { -// s.mockCtrl = gomock.NewController(s.T()) -// var err error - -// s.deviceDefSvc = mock_services.NewMockDeviceDefinitionService(s.mockCtrl) -// s.userClient = mock_services.NewMockUserServiceClient(s.mockCtrl) -// s.syntheticDeviceSigSvc = mock_services.NewMockSyntheticWalletInstanceService(s.mockCtrl) -// s.smartcarClient = mock_services.NewMockSmartcarClient(s.mockCtrl) -// s.teslaService = mock_services.NewMockTeslaService(s.mockCtrl) - -// mockProducer = smock.NewSyncProducer(s.T(), nil) - -// mockSettings := &config.Settings{Port: "3000", DIMORegistryChainID: 80001, DIMORegistryAddr: common.HexToAddress("0x4De1bCf2B7E851E31216fC07989caA902A604784").Hex()} -// mockSettings.DB.Name = "devices_api" - -// client := registry.Client{ -// Producer: mockProducer, -// RequestTopic: "topic.transaction.request.send", -// Contract: registry.Contract{ -// ChainID: big.NewInt(mockSettings.DIMORegistryChainID), -// Address: common.HexToAddress(mockSettings.DIMORegistryAddr), -// Name: "DIMO", -// Version: "1", -// }, -// } - -// if err != nil { -// s.T().Fatal(err) -// } - -// logger := test.Logger() - -// c := NewSyntheticDevicesController(mockSettings, s.pdb.DBS, logger, s.deviceDefSvc, s.userClient, s.syntheticDeviceSigSvc, client) -// s.sdc = c - -// app := test.SetupAppFiber(*logger) - -// app.Post("/v1/synthetic/device/mint/:integrationNode/:vehicleNode", test.AuthInjectorTestHandler(mockUserID), c.MintSyntheticDevice) -// app.Get("/v1/synthetic/device/mint/:integrationNode/:vehicleNode", test.AuthInjectorTestHandler(mockUserID), c.GetSyntheticDeviceMintingPayload) - -// s.app = app -// } - -// // TearDownTest after each test truncate tables -// func (s *SyntheticDevicesControllerTestSuite) TearDownTest() { -// test.TruncateTables(s.pdb.DBS().Writer.DB, s.T()) -// } +import ( + "context" + "encoding/json" + "fmt" + "io" + "math/big" + "testing" + + "github.com/DIMO-Network/devices-api/internal/config" + "github.com/DIMO-Network/devices-api/internal/contracts" + mock_services "github.com/DIMO-Network/devices-api/internal/services/mocks" + "github.com/DIMO-Network/devices-api/internal/services/registry" + "github.com/DIMO-Network/devices-api/internal/test" + "github.com/DIMO-Network/devices-api/models" + "github.com/DIMO-Network/shared" + "github.com/DIMO-Network/shared/api/users" + pb "github.com/DIMO-Network/shared/api/users" + "github.com/DIMO-Network/shared/db" + smock "github.com/Shopify/sarama/mocks" + "github.com/ericlagergren/decimal" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/secp256k1" + "github.com/gofiber/fiber/v2" + "github.com/golang/mock/gomock" + "github.com/pkg/errors" + "github.com/segmentio/ksuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "github.com/testcontainers/testcontainers-go" + "github.com/volatiletech/sqlboiler/v4/types" +) + +var signature = "0xa4438e5cb667dc63ebd694167ae3ad83585f2834c9b04895dd890f805c4c459a024ed9df1b03872536b4ac0c7720d02cb787884a093cfcde5c3bd7f94657e30c1b" +var userEthAddress = "0xd64E249A06ee6263d989e43aBFe12748a2506f88" +var mockProducer *smock.SyncProducer +var mockUserID = ksuid.New().String() + +type SyntheticDevicesControllerTestSuite struct { + suite.Suite + pdb db.Store + container testcontainers.Container + ctx context.Context + mockCtrl *gomock.Controller + app *fiber.App + deviceDefSvc *mock_services.MockDeviceDefinitionService + userClient *mock_services.MockUserServiceClient + sdc SyntheticDevicesController + syntheticDeviceSigSvc *mock_services.MockSyntheticWalletInstanceService + smartcarClient *mock_services.MockSmartcarClient + teslaService *mock_services.MockTeslaService +} + +// SetupSuite starts container db +func (s *SyntheticDevicesControllerTestSuite) SetupSuite() { + s.ctx = context.Background() + s.pdb, s.container = test.StartContainerDatabase(s.ctx, s.T(), migrationsDirRelPath) +} + +func (s *SyntheticDevicesControllerTestSuite) SetupTest() { + s.mockCtrl = gomock.NewController(s.T()) + var err error + + s.deviceDefSvc = mock_services.NewMockDeviceDefinitionService(s.mockCtrl) + s.userClient = mock_services.NewMockUserServiceClient(s.mockCtrl) + s.syntheticDeviceSigSvc = mock_services.NewMockSyntheticWalletInstanceService(s.mockCtrl) + s.smartcarClient = mock_services.NewMockSmartcarClient(s.mockCtrl) + s.teslaService = mock_services.NewMockTeslaService(s.mockCtrl) + + mockProducer = smock.NewSyncProducer(s.T(), nil) + + mockSettings := &config.Settings{Port: "3000", DIMORegistryChainID: 80001, DIMORegistryAddr: common.HexToAddress("0x4De1bCf2B7E851E31216fC07989caA902A604784").Hex()} + mockSettings.DB.Name = "devices_api" + + client := registry.Client{ + Producer: mockProducer, + RequestTopic: "topic.transaction.request.send", + Contract: registry.Contract{ + ChainID: big.NewInt(mockSettings.DIMORegistryChainID), + Address: common.HexToAddress(mockSettings.DIMORegistryAddr), + Name: "DIMO", + Version: "1", + }, + } + + if err != nil { + s.T().Fatal(err) + } + + logger := test.Logger() + + c := NewSyntheticDevicesController(mockSettings, s.pdb.DBS, logger, s.deviceDefSvc, s.userClient, s.syntheticDeviceSigSvc, client) + s.sdc = c + + app := test.SetupAppFiber(*logger) + + app.Post("/v1/user/devices/:userDeviceID/integrations/:integrationID/commands/mint", test.AuthInjectorTestHandler(mockUserID), c.MintSyntheticDevice) + app.Get("/v1/user/devices/:userDeviceID/integrations/:integrationID/commands/mint", test.AuthInjectorTestHandler(mockUserID), c.GetSyntheticDeviceMintingPayload) + + s.app = app +} + +// TearDownTest after each test truncate tables +func (s *SyntheticDevicesControllerTestSuite) TearDownTest() { + s.mockCtrl.Finish() + test.TruncateTables(s.pdb.DBS().Writer.DB, s.T()) +} + +// TearDownSuite cleanup at end by terminating container +func (s *SyntheticDevicesControllerTestSuite) TearDownSuite() { + if err := s.container.Terminate(s.ctx); err != nil { + s.T().Fatal(err) + } +} + +// Test Runner +func TestSyntheticDevicesControllerTestSuite(t *testing.T) { + suite.Run(t, new(SyntheticDevicesControllerTestSuite)) +} -// // TearDownSuite cleanup at end by terminating container -// func (s *SyntheticDevicesControllerTestSuite) TearDownSuite() { -// fmt.Printf("shutting down postgres at with session: %s \n", s.container.SessionID()) +func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload() { + _, addr, err := test.GenerateWallet() + s.Require().NoError(err) -// if err := s.container.Terminate(s.ctx); err != nil { -// s.T().Fatal(err) -// } -// s.mockCtrl.Finish() -// } + email := "some@email.com" + eth := addr.Hex() -// // Test Runner -// func TestSyntheticDevicesControllerTestSuite(t *testing.T) { -// suite.Run(t, new(SyntheticDevicesControllerTestSuite)) -// } + user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) + s.userClient.EXPECT().GetUser(gomock.Any(), &pb.GetUserRequest{Id: mockUserID}).Return(user, nil) -// func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload() { -// _, addr, err := test.GenerateWallet() -// assert.NoError(s.T(), err) + integration := test.BuildIntegrationForGRPCRequest(10, "SmartCar") + s.deviceDefSvc.EXPECT().GetIntegrationByID(gomock.Any(), integration.Id).Return(integration, nil) -// email := "some@email.com" -// eth := addr.Hex() + test.BuildDeviceDefinitionGRPC(ksuid.New().String(), "Ford", "Explorer", 2022, nil) -// user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) -// s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) + udID := ksuid.New().String() + test.SetupCreateVehicleNFTForMiddleware(s.T(), *addr, mockUserID, udID, 57, s.pdb) + test.SetupCreateUserDeviceAPIIntegration(s.T(), "", "xddL", udID, integration.Id, s.pdb) -// integrations := test.BuildIntegrationForGRPCRequest(10, uint64(1)) -// s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), gomock.Any()).Return(integrations, nil) + request := test.BuildRequest("GET", fmt.Sprintf("/v1/user/devices/%s/integrations/%s/commands/mint", udID, integration.Id), "") + response, err := s.app.Test(request) + s.Require().NoError(err) -// _ = test.BuildDeviceDefinitionGRPC(ksuid.New().String(), "Ford", "Explorer", 2022, nil) + body, _ := io.ReadAll(response.Body) -// udID := ksuid.New().String() -// _ = test.SetupCreateVehicleNFTForMiddleware(s.T(), *addr, mockUserID, udID, 57, s.pdb) + rawExpectedResp := s.sdc.getEIP712Mint(int64(10), int64(57)) + expectedRespJSON, err := json.Marshal(rawExpectedResp) + s.NoError(err) -// request := test.BuildRequest("GET", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), "") -// response, err := s.app.Test(request) -// require.NoError(s.T(), err) + s.Equal(fiber.StatusOK, response.StatusCode) + // TODO: This is a bit circular. + s.JSONEq(string(body), string(expectedRespJSON)) +} -// body, _ := io.ReadAll(response.Body) +func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload_UserDetailsError() { + _, addr, err := test.GenerateWallet() + s.Require().NoError(err) -// rawExpectedResp := s.sdc.getEIP712Mint(int64(1), int64(57)) -// expectedRespJSON, err := json.Marshal(rawExpectedResp) -// assert.NoError(s.T(), err) + s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(nil, errors.New("User not found")) -// assert.Equal(s.T(), fiber.StatusOK, response.StatusCode) -// assert.Equal(s.T(), body, expectedRespJSON) -// } + integration := test.BuildIntegrationForGRPCRequest(10, "SmartCar") -// func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload_UserNotFound() { -// s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(nil, errors.New("User not found")) + test.BuildDeviceDefinitionGRPC(ksuid.New().String(), "Ford", "Explorer", 2022, nil) -// request := test.BuildRequest("GET", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), "") -// response, err := s.app.Test(request) -// require.NoError(s.T(), err) + udID := ksuid.New().String() + test.SetupCreateVehicleNFTForMiddleware(s.T(), *addr, mockUserID, udID, 57, s.pdb) + test.SetupCreateUserDeviceAPIIntegration(s.T(), "", "xddL", udID, integration.Id, s.pdb) -// body, _ := io.ReadAll(response.Body) + request := test.BuildRequest("GET", fmt.Sprintf("/v1/user/devices/%s/integrations/%s/commands/mint", udID, integration.Id), "") + response, err := s.app.Test(request) + s.Require().NoError(err) -// assert.Equal(s.T(), fiber.StatusInternalServerError, response.StatusCode) -// assert.Equal(s.T(), []byte(fmt.Sprintf(`{"code":%d,"message":"error occurred when fetching user: User not found"}`, fiber.StatusInternalServerError)), body) -// } + body, _ := io.ReadAll(response.Body) -// func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload_NoEthereumAddressForUser() { -// email := "some@email.com" -// user := test.BuildGetUserGRPC(mockUserID, &email, nil, &users.UserReferrer{}) -// s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) + assert.Equal(s.T(), fiber.StatusInternalServerError, response.StatusCode) + assert.Equal(s.T(), []byte(fmt.Sprintf(`{"code":%d,"message":"error occurred when fetching user: User not found"}`, fiber.StatusInternalServerError)), body) +} -// request := test.BuildRequest("GET", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), "") -// response, err := s.app.Test(request) -// require.NoError(s.T(), err) +func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload_NoEthereumAddressForUser() { + _, addr, err := test.GenerateWallet() + s.Require().NoError(err) -// body, _ := io.ReadAll(response.Body) + email := "some@email.com" -// assert.Equal(s.T(), fiber.StatusUnauthorized, response.StatusCode) -// assert.Equal(s.T(), []byte(fmt.Sprintf(`{"code":%d,"message":"User does not have an Ethereum address."}`, fiber.StatusUnauthorized)), body) -// } + user := test.BuildGetUserGRPC(mockUserID, &email, nil, &users.UserReferrer{}) + s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) -// func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload_NoIntegrationForID() { -// _, addr, err := test.GenerateWallet() -// assert.NoError(s.T(), err) + integration := test.BuildIntegrationForGRPCRequest(10, "SmartCar") -// eth := addr.Hex() -// email := "some@email.com" + test.BuildDeviceDefinitionGRPC(ksuid.New().String(), "Ford", "Explorer", 2022, nil) -// user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) -// s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) + udID := ksuid.New().String() + test.SetupCreateVehicleNFTForMiddleware(s.T(), *addr, mockUserID, udID, 57, s.pdb) + test.SetupCreateUserDeviceAPIIntegration(s.T(), "", "xddL", udID, integration.Id, s.pdb) -// s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), gomock.Any()).Return(nil, errors.New("could not find integration")) + request := test.BuildRequest("GET", fmt.Sprintf("/v1/user/devices/%s/integrations/%s/commands/mint", udID, integration.Id), "") + response, err := s.app.Test(request) + s.Require().NoError(err) -// udID := ksuid.New().String() -// _ = test.SetupCreateVehicleNFTForMiddleware(s.T(), *addr, mockUserID, udID, 57, s.pdb) + body, _ := io.ReadAll(response.Body) -// request := test.BuildRequest("GET", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), "") -// response, err := s.app.Test(request) -// require.NoError(s.T(), err) + s.Equal(fiber.StatusUnauthorized, response.StatusCode) + s.JSONEq(`{"code":401,"message":"User does not have an Ethereum address."}`, string(body)) +} -// body, _ := io.ReadAll(response.Body) +func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload_GetIntegrationFailed() { + _, addr, err := test.GenerateWallet() + s.Require().NoError(err) -// assert.Equal(s.T(), fiber.StatusInternalServerError, response.StatusCode) -// assert.Equal(s.T(), []byte(fmt.Sprintf(`{"code":%d,"message":"failed to get integration: could not find integration"}`, fiber.StatusInternalServerError)), body) -// } + email := "some@email.com" + eth := addr.Hex() -// func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload_VehicleNodeNotExist() { -// _, addr, err := test.GenerateWallet() -// assert.NoError(s.T(), err) + user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) + s.userClient.EXPECT().GetUser(gomock.Any(), &pb.GetUserRequest{Id: mockUserID}).Return(user, nil) -// eth := addr.Hex() -// email := "some@email.com" + integration := test.BuildIntegrationForGRPCRequest(10, "SmartCar") + s.deviceDefSvc.EXPECT().GetIntegrationByID(gomock.Any(), integration.Id).Return(nil, errors.New("could not find integration")) -// user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) -// s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) + test.BuildDeviceDefinitionGRPC(ksuid.New().String(), "Ford", "Explorer", 2022, nil) -// request := test.BuildRequest("GET", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), "") -// response, err := s.app.Test(request) -// require.NoError(s.T(), err) + udID := ksuid.New().String() + test.SetupCreateVehicleNFTForMiddleware(s.T(), *addr, mockUserID, udID, 57, s.pdb) + test.SetupCreateUserDeviceAPIIntegration(s.T(), "", "xddL", udID, integration.Id, s.pdb) -// body, _ := io.ReadAll(response.Body) + request := test.BuildRequest("GET", fmt.Sprintf("/v1/user/devices/%s/integrations/%s/commands/mint", udID, integration.Id), "") + response, err := s.app.Test(request) + s.Require().NoError(err) -// assert.Equal(s.T(), fiber.StatusNotFound, response.StatusCode) -// assert.Equal(s.T(), []byte(fmt.Sprintf(`{"code":%d,"message":"No vehicle with that id found."}`, fiber.StatusNotFound)), body) -// } + body, _ := io.ReadAll(response.Body) -// func (s *SyntheticDevicesControllerTestSuite) Test_MintSyntheticDeviceSmartcar() { -// email := "some@email.com" -// eth := userEthAddress -// addr := common.HexToAddress(userEthAddress) -// deviceEthAddr := common.HexToAddress("11") + s.Equal(fiber.StatusInternalServerError, response.StatusCode) + s.JSONEq(`{"code":500,"message":"failed to get integration: could not find integration"}`, string(body)) +} -// user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) -// s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) +func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPayload_VehicleNodeNotExist() { + _, addr, err := test.GenerateWallet() + s.Require().NoError(err) -// scInt := &ddgrpc.Integration{ -// Id: "22N2xaPOq2WW2gAHBHd0Ikn4Zob", -// Vendor: "SmartCar", -// TokenId: 1, -// } + email := "some@email.com" + eth := addr.Hex() -// s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), uint64(1)).Return(scInt, nil) + user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) + s.userClient.EXPECT().GetUser(gomock.Any(), &pb.GetUserRequest{Id: mockUserID}).Return(user, nil) -// _ = test.BuildDeviceDefinitionGRPC(ksuid.New().String(), "Ford", "Explorer", 2022, nil) + integration := test.BuildIntegrationForGRPCRequest(10, "SmartCar") -// udID := ksuid.New().String() -// vehicle := test.SetupCreateVehicleNFTForMiddleware(s.T(), addr, mockUserID, udID, 57, s.pdb) + test.BuildDeviceDefinitionGRPC(ksuid.New().String(), "Ford", "Explorer", 2022, nil) -// vehicleSig := common.HexToAddress("20").Hash().Bytes() -// s.syntheticDeviceSigSvc.EXPECT().SignHash(gomock.Any(), gomock.Any(), gomock.Any()).Return(vehicleSig, nil).AnyTimes() -// s.syntheticDeviceSigSvc.EXPECT().GetAddress(gomock.Any(), gomock.Any()).Return(deviceEthAddr.Bytes(), nil).AnyTimes() + udID := ksuid.New().String() -// s.smartcarClient.EXPECT().ExchangeCode(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockSmartClientToken, nil) -// s.smartcarClient.EXPECT().GetExternalID(gomock.Any(), gomock.Any()).Return("smartcarVehicleId", nil) -// s.smartcarClient.EXPECT().GetEndpoints(gomock.Any(), gomock.Any(), gomock.Any()).Return([]string{"/odometer", "/location"}, nil) -// s.smartcarClient.EXPECT().HasDoorControl(gomock.Any(), mockSmartClientToken.Access, "smartcarVehicleId").Return(true, nil) + request := test.BuildRequest("GET", fmt.Sprintf("/v1/user/devices/%s/integrations/%s/commands/mint", udID, integration.Id), "") + response, err := s.app.Test(request) + s.Require().NoError(err) -// var kb []byte -// mockProducer.ExpectSendMessageWithCheckerFunctionAndSucceed(func(val []byte) error { -// kb = val -// return nil -// }) + body, _ := io.ReadAll(response.Body) -// req := fmt.Sprintf(`{ -// "credentials": { -// "code": "a4d04dad-2b65-4778-94b7-f04996e89907" -// }, -// "ownerSignature": "%s" -// }`, signature) + assert.Equal(s.T(), fiber.StatusNotFound, response.StatusCode) + assert.Equal(s.T(), []byte(fmt.Sprintf(`{"code":%d,"message":"No vehicle with that id found."}`, fiber.StatusNotFound)), body) +} -// request := test.BuildRequest("POST", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), req) -// response, err := s.app.Test(request) -// require.NoError(s.T(), err) +func (s *SyntheticDevicesControllerTestSuite) Test_MintSyntheticDeviceSmartcar() { + _, addr, err := test.GenerateWallet() + s.Require().NoError(err) -// body, _ := io.ReadAll(response.Body) + email := "some@email.com" + eth := userEthAddress + // addr := common.HexToAddress(userEthAddress) + deviceEthAddr := common.HexToAddress("11") -// assert.Equal(s.T(), fiber.StatusOK, response.StatusCode) + user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) + s.userClient.EXPECT().GetUser(gomock.Any(), &pb.GetUserRequest{Id: mockUserID}).Return(user, nil) -// mockProducer.Close() + integration := test.BuildIntegrationForGRPCRequest(1, "SmartCar") + s.deviceDefSvc.EXPECT().GetIntegrationByID(gomock.Any(), integration.Id).Return(integration, nil) -// assert.Equal(s.T(), "{\"message\":\"Submitted synthetic device mint request.\"}", string(body)) + test.BuildDeviceDefinitionGRPC(ksuid.New().String(), "Ford", "Explorer", 2022, nil) -// var me shared.CloudEvent[registry.RequestData] + udID := ksuid.New().String() + test.SetupCreateVehicleNFTForMiddleware(s.T(), *addr, mockUserID, udID, 57, s.pdb) + test.SetupCreateUserDeviceAPIIntegration(s.T(), "", "xddL", udID, integration.Id, s.pdb) -// err = json.Unmarshal(kb, &me) -// s.Require().NoError(err) + vehicleSig := common.HexToAddress("20").Hash().Bytes() + s.syntheticDeviceSigSvc.EXPECT().SignHash(gomock.Any(), gomock.Any(), gomock.Any()).Return(vehicleSig, nil).AnyTimes() + s.syntheticDeviceSigSvc.EXPECT().GetAddress(gomock.Any(), gomock.Any()).Return(deviceEthAddr.Bytes(), nil).AnyTimes() -// abi, err := contracts.RegistryMetaData.GetAbi() -// s.Require().NoError(err) + var kb []byte + mockProducer.ExpectSendMessageWithCheckerFunctionAndSucceed(func(val []byte) error { + kb = val + return nil + }) -// method := abi.Methods["mintSyntheticDeviceSign"] + req := fmt.Sprintf(`{ + "signature": "%s" + }`, signature) -// callData := me.Data.Data + request := test.BuildRequest("POST", fmt.Sprintf("/v1/user/devices/%s/integrations/%s/commands/mint", udID, integration.Id), req) + response, err := s.app.Test(request) + s.Require().NoError(err) -// s.EqualValues(method.ID, callData[:4]) + body, _ := io.ReadAll(response.Body) -// o, err := method.Inputs.Unpack(callData[4:]) -// s.Require().NoError(err) + assert.Equal(s.T(), fiber.StatusOK, response.StatusCode) -// actualMnInput := o[0].(struct { -// IntegrationNode *big.Int `json:"integrationNode"` -// VehicleNode *big.Int `json:"vehicleNode"` -// SyntheticDeviceSig []uint8 `json:"syntheticDeviceSig"` -// VehicleOwnerSig []uint8 `json:"vehicleOwnerSig"` -// SyntheticDeviceAddr common.Address `json:"syntheticDeviceAddr"` -// AttrInfoPairs []struct { -// Attribute string `json:"attribute"` -// Info string `json:"info"` -// } `json:"attrInfoPairs"` -// }) + mockProducer.Close() -// expectedMnInput := contracts.MintSyntheticDeviceInput{ -// IntegrationNode: new(big.Int).SetUint64(1), -// VehicleNode: new(big.Int).SetUint64(57), -// VehicleOwnerSig: common.FromHex(signature), -// SyntheticDeviceAddr: deviceEthAddr, -// SyntheticDeviceSig: vehicleSig, -// } + assert.Equal(s.T(), "{\"message\":\"Submitted synthetic device mint request.\"}", string(body)) -// vnID := types.NewNullDecimal(decimal.New(57, 0)) -// syntDevice, err := models.SyntheticDevices( -// models.SyntheticDeviceWhere.VehicleTokenID.EQ(vnID), -// models.SyntheticDeviceWhere.IntegrationTokenID.EQ(types.NewDecimal(decimal.New(1, 0))), -// ).One(s.ctx, s.pdb.DBS().Reader) -// assert.NoError(s.T(), err) + var me shared.CloudEvent[registry.RequestData] -// assert.Equal(s.T(), syntDevice.IntegrationTokenID, types.NewDecimal(decimal.New(1, 0))) -// assert.Equal(s.T(), syntDevice.VehicleTokenID, vnID) + err = json.Unmarshal(kb, &me) + s.Require().NoError(err) -// assert.ObjectsAreEqual(expectedMnInput, actualMnInput) + abi, err := contracts.RegistryMetaData.GetAbi() + s.Require().NoError(err) -// metaTrxReq, err := models.MetaTransactionRequests( -// models.MetaTransactionRequestWhere.ID.EQ(syntDevice.MintRequestID), -// models.MetaTransactionRequestWhere.Status.EQ(models.MetaTransactionRequestStatusUnsubmitted), -// ).Exists(s.ctx, s.pdb.DBS().Reader) -// assert.NoError(s.T(), err) + method := abi.Methods["mintSyntheticDeviceSign"] -// assert.Equal(s.T(), metaTrxReq, true) + callData := me.Data.Data -// udis, err := models.UserDeviceAPIIntegrations().All(s.ctx, s.pdb.DBS().Reader) -// assert.NoError(s.T(), err) + s.EqualValues(method.ID, callData[:4]) -// assert.Equal(s.T(), 1, len(udis)) + o, err := method.Inputs.Unpack(callData[4:]) + s.Require().NoError(err) -// decAccessToken, err := s.sdc.cipher.Decrypt(udis[0].AccessToken.String) -// assert.NoError(s.T(), err) + actualMnInput := o[0].(struct { + IntegrationNode *big.Int `json:"integrationNode"` + VehicleNode *big.Int `json:"vehicleNode"` + SyntheticDeviceSig []uint8 `json:"syntheticDeviceSig"` + VehicleOwnerSig []uint8 `json:"vehicleOwnerSig"` + SyntheticDeviceAddr common.Address `json:"syntheticDeviceAddr"` + AttrInfoPairs []struct { + Attribute string `json:"attribute"` + Info string `json:"info"` + } `json:"attrInfoPairs"` + }) -// decRefreshToken, err := s.sdc.cipher.Decrypt(udis[0].RefreshToken.String) -// assert.NoError(s.T(), err) + expectedMnInput := contracts.MintSyntheticDeviceInput{ + IntegrationNode: new(big.Int).SetUint64(1), + VehicleNode: new(big.Int).SetUint64(57), + VehicleOwnerSig: common.FromHex(signature), + SyntheticDeviceAddr: deviceEthAddr, + SyntheticDeviceSig: vehicleSig, + } -// assert.Equal(s.T(), scInt.Id, udis[0].IntegrationID) -// assert.Equal(s.T(), vehicle.UserDeviceID.String, udis[0].UserDeviceID) -// assert.Equal(s.T(), mockSmartClientToken.Access, decAccessToken) -// assert.Equal(s.T(), mockSmartClientToken.Refresh, decRefreshToken) -// } + vnID := types.NewNullDecimal(decimal.New(57, 0)) + syntDevice, err := models.SyntheticDevices( + models.SyntheticDeviceWhere.VehicleTokenID.EQ(vnID), + models.SyntheticDeviceWhere.IntegrationTokenID.EQ(types.NewDecimal(decimal.New(1, 0))), + ).One(s.ctx, s.pdb.DBS().Reader) + assert.NoError(s.T(), err) -// func (s *SyntheticDevicesControllerTestSuite) TestMintTesla() { -// email := "some@email.com" -// userEthAddress := "0xFdC646Ad5950ED5cBf2A203C4D8001551b3Ee752" -// signature := "0xee3235ef51bd273ec6533db4fe8038add3461bcde83e35d0043d94b4a58d7ba10a9e4648694e45daab12ac5617dffed1a84232e49885dfaf651dbe5e97d349bd1b" -// eth := userEthAddress -// addr := common.HexToAddress(userEthAddress) -// deviceEthAddr := common.HexToAddress("10") -// integrationID := 2 -// vehicleNode := 56 + assert.Equal(s.T(), syntDevice.IntegrationTokenID, types.NewDecimal(decimal.New(1, 0))) + assert.Equal(s.T(), syntDevice.VehicleTokenID, vnID) -// user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) -// s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) + assert.ObjectsAreEqual(expectedMnInput, actualMnInput) -// integration := test.BuildIntegrationForGRPCRequest(10, uint64(integrationID)) -// integration.Vendor = constants.TeslaVendor -// integration.TokenId = 2 -// s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), gomock.Any()).Return(integration, nil) + metaTrxReq, err := models.MetaTransactionRequests( + models.MetaTransactionRequestWhere.ID.EQ(syntDevice.MintRequestID), + models.MetaTransactionRequestWhere.Status.EQ(models.MetaTransactionRequestStatusUnsubmitted), + ).Exists(s.ctx, s.pdb.DBS().Reader) + assert.NoError(s.T(), err) -// _ = test.BuildDeviceDefinitionGRPC(ksuid.New().String(), "Tesla", "Model X", 2022, nil) + assert.Equal(s.T(), metaTrxReq, true) +} -// udID := ksuid.New().String() -// vehicle := test.SetupCreateVehicleNFTForMiddleware(s.T(), addr, mockUserID, udID, int64(vehicleNode), s.pdb) +func (s *SyntheticDevicesControllerTestSuite) TestSignSyntheticDeviceMintingPayload_BadSignatureFailure() { + _, addr, err := test.GenerateWallet() + s.Require().NoError(err) -// vehicleSig := common.HexToAddress("20").Hash().Bytes() -// s.syntheticDeviceSigSvc.EXPECT().SignHash(gomock.Any(), gomock.Any(), gomock.Any()).Return(vehicleSig, nil).AnyTimes() -// s.syntheticDeviceSigSvc.EXPECT().GetAddress(gomock.Any(), gomock.Any()).Return(deviceEthAddr.Bytes(), nil).AnyTimes() + email := "some@email.com" + eth := addr.Hex() -// teslaData := services.TeslaVehicle{ID: 13, VehicleID: 666, VIN: "5YJYGDEE9MF073630"} -// s.teslaService.EXPECT().GetVehicle(gomock.Any(), gomock.Any()).Return(&teslaData, nil) + user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) + s.userClient.EXPECT().GetUser(gomock.Any(), &pb.GetUserRequest{Id: mockUserID}).Return(user, nil) -// var kb []byte -// mockProducer.ExpectSendMessageWithCheckerFunctionAndSucceed(func(val []byte) error { -// kb = val -// return nil -// }) + integration := test.BuildIntegrationForGRPCRequest(10, "SmartCar") + s.deviceDefSvc.EXPECT().GetIntegrationByID(gomock.Any(), integration.Id).Return(integration, nil) -// teslaClientToken.OwnerSignature = signature -// reqB, err := json.Marshal(teslaClientToken) -// s.NoError(err) - -// request := test.BuildRequest("POST", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", integrationID, vehicleNode), string(reqB)) -// response, err := s.app.Test(request) -// require.NoError(s.T(), err) - -// body, _ := io.ReadAll(response.Body) - -// assert.Equal(s.T(), fiber.StatusOK, response.StatusCode) -// mockProducer.Close() - -// assert.Equal(s.T(), "{\"message\":\"Submitted synthetic device mint request.\"}", string(body)) - -// var me shared.CloudEvent[registry.RequestData] + test.BuildDeviceDefinitionGRPC(ksuid.New().String(), "Ford", "Explorer", 2022, nil) -// err = json.Unmarshal(kb, &me) -// s.Require().NoError(err) - -// abi, err := contracts.RegistryMetaData.GetAbi() -// s.Require().NoError(err) + udID := ksuid.New().String() + test.SetupCreateVehicleNFTForMiddleware(s.T(), *addr, mockUserID, udID, 57, s.pdb) + test.SetupCreateUserDeviceAPIIntegration(s.T(), "", "xddL", udID, integration.Id, s.pdb) -// method := abi.Methods["mintSyntheticDeviceSign"] + req := `{ + "signature": "0xa3438e5cb667dc63ebd694167ae3ad83585f2834c9b04895dd890f805c4c459a024ed9df1b03872536b4ac0c7720d02cb787884a093cfcde5c3bd7f94657e30c1b" + }` + request := test.BuildRequest("POST", fmt.Sprintf("/v1/user/devices/%s/integrations/%s/commands/mint", udID, integration.Id), req) + response, err := s.app.Test(request) + s.Require().NoError(err) -// callData := me.Data.Data + body, _ := io.ReadAll(response.Body) -// s.EqualValues(method.ID, callData[:4]) + msg := struct { + Message string `json:"message"` + }{} + err = json.Unmarshal(body, &msg) + s.NoError(err) + assert.Equal(s.T(), fiber.StatusInternalServerError, response.StatusCode) + assert.Equal(s.T(), secp256k1.ErrRecoverFailed.Error(), msg.Message) -// o, err := method.Inputs.Unpack(callData[4:]) -// s.Require().NoError(err) + // // -// actualMnInput := o[0].(struct { -// IntegrationNode *big.Int `json:"integrationNode"` -// VehicleNode *big.Int `json:"vehicleNode"` -// SyntheticDeviceSig []uint8 `json:"syntheticDeviceSig"` -// VehicleOwnerSig []uint8 `json:"vehicleOwnerSig"` -// SyntheticDeviceAddr common.Address `json:"syntheticDeviceAddr"` -// AttrInfoPairs []struct { -// Attribute string `json:"attribute"` -// Info string `json:"info"` -// } `json:"attrInfoPairs"` -// }) + // email := "some@email.com" + // eth := userEthAddress -// expectedMnInput := contracts.MintSyntheticDeviceInput{ -// IntegrationNode: new(big.Int).SetUint64(uint64(integrationID)), -// VehicleNode: new(big.Int).SetUint64(uint64(vehicleNode)), -// VehicleOwnerSig: common.FromHex(signature), -// SyntheticDeviceAddr: deviceEthAddr, -// SyntheticDeviceSig: vehicleSig, -// } + // user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) + // s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) -// vnID := types.NewNullDecimal(decimal.New(int64(vehicleNode), 0)) -// syntDevice, err := models.SyntheticDevices( -// models.SyntheticDeviceWhere.VehicleTokenID.EQ(vnID), -// models.SyntheticDeviceWhere.IntegrationTokenID.EQ(types.NewDecimal(decimal.New(int64(integrationID), 0))), -// ).One(s.ctx, s.pdb.DBS().Reader) -// assert.NoError(s.T(), err) + // scInt := &ddgrpc.Integration{ + // Id: "22N2xaPOq2WW2gAHBHd0Ikn4Zob", + // Vendor: "SmartCar", + // TokenId: 1, + // } -// assert.Equal(s.T(), syntDevice.IntegrationTokenID, types.NewDecimal(decimal.New(int64(integrationID), 0))) -// assert.Equal(s.T(), syntDevice.VehicleTokenID, vnID) + // s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), uint64(1)).Return(scInt, nil) -// assert.ObjectsAreEqual(expectedMnInput, actualMnInput) + // udID := ksuid.New().String() + // _ = test.SetupCreateVehicleNFTForMiddleware(s.T(), common.HexToAddress(userEthAddress), mockUserID, udID, 57, s.pdb) + + // req := `{ + // "ownerSignature": "0xa3438e5cb667dc63ebd694167ae3ad83585f2834c9b04895dd890f805c4c459a024ed9df1b03872536b4ac0c7720d02cb787884a093cfcde5c3bd7f94657e30c1b" + // }` + // request := test.BuildRequest("POST", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), req) + // response, err := s.app.Test(request) + // require.NoError(s.T(), err) + + // body, _ := io.ReadAll(response.Body) + + // msg := struct { + // Message string `json:"message"` + // }{} -// metaTrxReq, err := models.MetaTransactionRequests( -// models.MetaTransactionRequestWhere.ID.EQ(syntDevice.MintRequestID), -// models.MetaTransactionRequestWhere.Status.EQ(models.MetaTransactionRequestStatusUnsubmitted), -// ).Exists(s.ctx, s.pdb.DBS().Reader) -// assert.NoError(s.T(), err) - -// assert.Equal(s.T(), metaTrxReq, true) - -// udi, err := models.UserDeviceAPIIntegrations(models.UserDeviceAPIIntegrationWhere.UserDeviceID.EQ(udID)).One(s.ctx, s.pdb.DBS().Reader) -// assert.NoError(s.T(), err) - -// decryptedAccessTkn, err := s.sdc.cipher.Decrypt(udi.AccessToken.String) -// assert.NoError(s.T(), err) - -// decryptedRefreshTkn, err := s.sdc.cipher.Decrypt(udi.RefreshToken.String) -// assert.NoError(s.T(), err) - -// assert.Equal(s.T(), integration.Id, udi.IntegrationID) -// assert.Equal(s.T(), vehicle.UserDeviceID.String, udi.UserDeviceID) -// assert.Equal(s.T(), teslaClientToken.Credentials.AccessToken, decryptedAccessTkn) -// assert.Equal(s.T(), teslaClientToken.Credentials.RefreshToken, decryptedRefreshTkn) -// } - -// func (s *SyntheticDevicesControllerTestSuite) TestSignSyntheticDeviceMintingPayload_BadSignatureFailure() { -// email := "some@email.com" -// eth := userEthAddress - -// user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) -// s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) - -// scInt := &ddgrpc.Integration{ -// Id: "22N2xaPOq2WW2gAHBHd0Ikn4Zob", -// Vendor: "SmartCar", -// TokenId: 1, -// } - -// s.deviceDefSvc.EXPECT().GetIntegrationByTokenID(gomock.Any(), uint64(1)).Return(scInt, nil) - -// udID := ksuid.New().String() -// _ = test.SetupCreateVehicleNFTForMiddleware(s.T(), common.HexToAddress(userEthAddress), mockUserID, udID, 57, s.pdb) - -// req := fmt.Sprintf(`{ -// "credentials": { -// "code": "a4d04dad-2b65-4778-94b7-f04996e89907" -// }, -// "ownerSignature": "%s" -// }`, "0xa3438e5cb667dc63ebd694167ae3ad83585f2834c9b04895dd890f805c4c459a024ed9df1b03872536b4ac0c7720d02cb787884a093cfcde5c3bd7f94657e30c1b") -// request := test.BuildRequest("POST", fmt.Sprintf("/v1/synthetic/device/mint/%d/%d", 1, 57), req) -// response, err := s.app.Test(request) -// require.NoError(s.T(), err) - -// body, _ := io.ReadAll(response.Body) - -// msg := struct { -// Message string `json:"message"` -// }{} -// err = json.Unmarshal(body, &msg) -// s.NoError(err) - -// assert.Equal(s.T(), fiber.StatusInternalServerError, response.StatusCode) -// assert.Equal(s.T(), secp256k1.ErrRecoverFailed.Error(), msg.Message) -// } - -// func (s *SyntheticDevicesControllerTestSuite) Test_Synthetic_Device_Sequence() { -// s.pdb, s.container = test.StartContainerDatabase(s.ctx, s.T(), migrationsDirRelPath) // resets sequence in pg, if removed, must account for Tesla and Smartcar mints above - -// syntDeviceCount, err := models.SyntheticDevices().Count(s.ctx, s.pdb.DBS().Reader) // expect that count will be 0 -// assert.NoError(s.T(), err) - -// childKeyNumber, err := s.sdc.generateNextChildKeyNumber(s.ctx) -// assert.NoError(s.T(), err) - -// assert.Equal(s.T(), int(syntDeviceCount)+1, childKeyNumber) - -// childKeyNumber, err = s.sdc.generateNextChildKeyNumber(s.ctx) -// assert.NoError(s.T(), err) - -// assert.Equal(s.T(), int(syntDeviceCount)+2, childKeyNumber) -// } +} diff --git a/internal/test/helpers.go b/internal/test/helpers.go index a2e0b6835..5d8a1c898 100644 --- a/internal/test/helpers.go +++ b/internal/test/helpers.go @@ -548,13 +548,13 @@ func GenerateWallet() (*ecdsa.PrivateKey, *common.Address, error) { } // BuildIntegrationForGRPCRequest includes tokenID when creating mock integration -func BuildIntegrationForGRPCRequest(autoPiDefaultTemplateID int, tokenID uint64) *ddgrpc.Integration { +func BuildIntegrationForGRPCRequest(tokenID uint64, vendor string) *ddgrpc.Integration { integration := &ddgrpc.Integration{ Id: ksuid.New().String(), Type: constants.IntegrationTypeHardware, Style: constants.IntegrationStyleAddon, - Vendor: constants.AutoPiVendor, - AutoPiDefaultTemplateId: int32(autoPiDefaultTemplateID), + Vendor: vendor, + AutoPiDefaultTemplateId: 0, TokenId: tokenID, } From 5f907529d0260e874eabd672fa583264bc51184f Mon Sep 17 00:00:00 2001 From: Dylan Moreland Date: Tue, 25 Jul 2023 22:29:33 -0400 Subject: [PATCH 11/11] Bring back the burn --- cmd/devices-api/api.go | 3 + .../synthetic_devices_controller.go | 174 ++++++++++++++++++ .../synthetic_devices_controller_test.go | 15 +- 3 files changed, 184 insertions(+), 8 deletions(-) diff --git a/cmd/devices-api/api.go b/cmd/devices-api/api.go index e8494d036..477f021d6 100644 --- a/cmd/devices-api/api.go +++ b/cmd/devices-api/api.go @@ -289,6 +289,9 @@ func startWebAPI(logger zerolog.Logger, settings *config.Settings, pdb db.Store, udOwner.Get("/integrations/:integrationID/commands/mint", syntheticController.GetSyntheticDeviceMintingPayload) udOwner.Post("/integrations/:integrationID/commands/mint", syntheticController.MintSyntheticDevice) + + v1Auth.Get("synthetic/device/:syntheticDeviceNode/burn", syntheticController.GetSyntheticDeviceBurnPayload) + v1Auth.Post("synthetic/device/:syntheticDeviceNode/burn", syntheticController.BurnSyntheticDevice) } // Vehicle commands. diff --git a/internal/controllers/synthetic_devices_controller.go b/internal/controllers/synthetic_devices_controller.go index f27f54442..23071e04a 100644 --- a/internal/controllers/synthetic_devices_controller.go +++ b/internal/controllers/synthetic_devices_controller.go @@ -5,6 +5,7 @@ import ( "database/sql" "fmt" "math/big" + "strconv" "github.com/DIMO-Network/devices-api/internal/config" "github.com/DIMO-Network/devices-api/internal/constants" @@ -22,6 +23,7 @@ import ( "github.com/gofiber/fiber/v2" "github.com/rs/zerolog" "github.com/segmentio/ksuid" + "github.com/volatiletech/null/v8" "github.com/volatiletech/sqlboiler/v4/boil" "github.com/volatiletech/sqlboiler/v4/queries" "github.com/volatiletech/sqlboiler/v4/queries/qm" @@ -306,6 +308,150 @@ func (sdc *SyntheticDevicesController) MintSyntheticDevice(c *fiber.Ctx) error { return c.JSON(fiber.Map{"message": "Submitted synthetic device mint request."}) } +// GetSyntheticDeviceBurnPayload godoc +// @Description Produces the payload that the user signs and submits to burn a synthetic device. +// @Produce json +// @Param syntheticDeviceNode path int true "synthetic device token id" +// @Success 200 {array} signer.TypedData +// @Router /synthetic/device/{syntheticDeviceNode}/burn [get] +func (sdc *SyntheticDevicesController) GetSyntheticDeviceBurnPayload(c *fiber.Ctx) error { + syntheticDeviceNodeRaw := c.Params("syntheticDeviceNode") + userID := helpers.GetUserID(c) + + syntheticDeviceNode, err := strconv.ParseInt(syntheticDeviceNodeRaw, 10, 64) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Node id %q must be an integer.", syntheticDeviceNodeRaw)) + } + + sd, err := models.SyntheticDevices( + models.SyntheticDeviceWhere.TokenID.EQ(types.NewNullDecimal(decimal.New(syntheticDeviceNode, 0))), + qm.Load(models.SyntheticDeviceRels.VehicleToken), + ).One(c.Context(), sdc.DBS().Reader) + if err != nil { + if err == sql.ErrNoRows { + return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("No device with id %d found.", syntheticDeviceNode)) + } + return err + } + + vOwn := common.BytesToAddress(sd.R.VehicleToken.OwnerAddress.Bytes) + + user, err := sdc.usersClient.GetUser(c.Context(), &pb.GetUserRequest{Id: userID}) + if err != nil { + sdc.log.Debug().Err(err).Msg("error occurred when fetching user") + return helpers.GrpcErrorToFiber(err, "error occurred when fetching user") + } + + if user.EthereumAddress == nil { + return fiber.NewError(fiber.StatusForbidden, "No Ethereum address on file for user.") + } + + addr := common.HexToAddress(*user.EthereumAddress) + + if vOwn != addr { + return fiber.NewError(fiber.StatusForbidden, fmt.Sprintf("Vehicle is owned by %s, your address is %s.", vOwn, addr)) + } + + vehicleNode, _ := sd.VehicleTokenID.Int64() + + return c.JSON(sdc.getEIP712Burn(vehicleNode, syntheticDeviceNode)) +} + +type BurnSyntheticDeviceRequest struct { + OwnerSignature string `json:"ownerSignature"` +} + +// BurnSyntheticDevice godoc +// @Description Submit the signature required for the synthetic device burning meta-transaction. +// @Produce json +// @Param syntheticDeviceNode path int true "synthetic device token id" +// @Success 200 +// @Router /synthetic/device/{syntheticDeviceNode}/burn [post] +func (sdc *SyntheticDevicesController) BurnSyntheticDevice(c *fiber.Ctx) error { + syntheticDeviceNodeRaw := c.Params("syntheticDeviceNode") + userID := helpers.GetUserID(c) + + syntheticDeviceNode, err := strconv.ParseInt(syntheticDeviceNodeRaw, 10, 64) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Node id %q must be an integer.", syntheticDeviceNodeRaw)) + } + + sd, err := models.SyntheticDevices( + models.SyntheticDeviceWhere.TokenID.EQ(types.NewNullDecimal(decimal.New(syntheticDeviceNode, 0))), + qm.Load(models.SyntheticDeviceRels.VehicleToken), + ).One(c.Context(), sdc.DBS().Reader) + if err != nil { + if err == sql.ErrNoRows { + return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("No device with id %d found.", syntheticDeviceNode)) + } + return err + } + + vOwn := common.BytesToAddress(sd.R.VehicleToken.OwnerAddress.Bytes) + + user, err := sdc.usersClient.GetUser(c.Context(), &pb.GetUserRequest{Id: userID}) + if err != nil { + sdc.log.Debug().Err(err).Msg("error occurred when fetching user") + return helpers.GrpcErrorToFiber(err, "error occurred when fetching user") + } + + if user.EthereumAddress == nil { + return fiber.NewError(fiber.StatusForbidden, "No Ethereum address on file for user.") + } + + addr := common.HexToAddress(*user.EthereumAddress) + + if vOwn != addr { + return fiber.NewError(fiber.StatusForbidden, fmt.Sprintf("Vehicle is owned by %s, your address is %s.", vOwn, addr)) + } + + vehicleNode, _ := sd.VehicleTokenID.Int64() + + td := sdc.getEIP712Burn(vehicleNode, syntheticDeviceNode) + + var req BurnSyntheticDeviceRequest + if err := c.BodyParser(&req); err != nil { + return fiber.NewError(fiber.StatusBadRequest, "Couldn't parse request body.") + } + + ownerSignature := common.FromHex(req.OwnerSignature) + if len(ownerSignature) != 65 { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Owner signature was length %d, not 65.", len(ownerSignature))) + } + + hash, _, err := signer.TypedDataAndHash(*td) + if err != nil { + sdc.log.Err(err).Msg("Error occurred creating has of payload") + return fiber.NewError(fiber.StatusBadRequest, "Couldn't verify signature.") + } + + if recAddr, err := helpers.Ecrecover(hash, ownerSignature); err != nil { + return err + } else if recAddr != addr { + return fiber.NewError(fiber.StatusBadRequest, "Invalid signature.") + } + + reqID := ksuid.New().String() + + if err := sdc.registryClient.BurnSyntheticDeviceSign(reqID, big.NewInt(vehicleNode), big.NewInt(syntheticDeviceNode), ownerSignature); err != nil { + return err + } + + mtr := models.MetaTransactionRequest{ + ID: reqID, + Status: models.MetaTransactionRequestStatusUnsubmitted, + } + + if err := mtr.Insert(c.Context(), sdc.DBS().Writer, boil.Infer()); err != nil { + return err + } + + sd.BurnRequestID = null.StringFrom(reqID) + _, err = sd.Update(c.Context(), sdc.DBS().Writer, boil.Infer()) + + return err +} + func (sdc *SyntheticDevicesController) sendSyntheticDeviceMintPayload(ctx context.Context, requestID string, hash []byte, vehicleNode int, intTokenID uint64, ownerSignature []byte, childKeyNumber int) ([]byte, error) { syntheticDeviceAddr, err := sdc.walletSvc.GetAddress(ctx, uint32(childKeyNumber)) if err != nil { @@ -349,3 +495,31 @@ func (sdc *SyntheticDevicesController) generateNextChildKeyNumber(ctx context.Co return seq.NextVal, nil } + +func (sdc *SyntheticDevicesController) getEIP712Burn(vehicleNode, syntheticDeviceNode int64) *signer.TypedData { + return &signer.TypedData{ + Types: signer.Types{ + "EIP712Domain": []signer.Type{ + {Name: "name", Type: "string"}, + {Name: "version", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + }, + "BurnSyntheticDeviceSign": []signer.Type{ + {Name: "vehicleNode", Type: "uint256"}, + {Name: "syntheticDeviceNode", Type: "uint256"}, + }, + }, + PrimaryType: "BurnSyntheticDeviceSign", + Domain: signer.TypedDataDomain{ + Name: "DIMO", + Version: "1", + ChainId: math.NewHexOrDecimal256(sdc.Settings.DIMORegistryChainID), + VerifyingContract: sdc.Settings.DIMORegistryAddr, + }, + Message: signer.TypedDataMessage{ + "vehicleNode": math.NewHexOrDecimal256(vehicleNode), + "syntheticDeviceNode": math.NewHexOrDecimal256(syntheticDeviceNode), + }, + } +} diff --git a/internal/controllers/synthetic_devices_controller_test.go b/internal/controllers/synthetic_devices_controller_test.go index 0e1f68358..23f500aa9 100644 --- a/internal/controllers/synthetic_devices_controller_test.go +++ b/internal/controllers/synthetic_devices_controller_test.go @@ -15,7 +15,6 @@ import ( "github.com/DIMO-Network/devices-api/internal/test" "github.com/DIMO-Network/devices-api/models" "github.com/DIMO-Network/shared" - "github.com/DIMO-Network/shared/api/users" pb "github.com/DIMO-Network/shared/api/users" "github.com/DIMO-Network/shared/db" smock "github.com/Shopify/sarama/mocks" @@ -126,7 +125,7 @@ func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPaylo email := "some@email.com" eth := addr.Hex() - user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) + user := test.BuildGetUserGRPC(mockUserID, &email, ð, &pb.UserReferrer{}) s.userClient.EXPECT().GetUser(gomock.Any(), &pb.GetUserRequest{Id: mockUserID}).Return(user, nil) integration := test.BuildIntegrationForGRPCRequest(10, "SmartCar") @@ -183,7 +182,7 @@ func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPaylo email := "some@email.com" - user := test.BuildGetUserGRPC(mockUserID, &email, nil, &users.UserReferrer{}) + user := test.BuildGetUserGRPC(mockUserID, &email, nil, &pb.UserReferrer{}) s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) integration := test.BuildIntegrationForGRPCRequest(10, "SmartCar") @@ -211,7 +210,7 @@ func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPaylo email := "some@email.com" eth := addr.Hex() - user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) + user := test.BuildGetUserGRPC(mockUserID, &email, ð, &pb.UserReferrer{}) s.userClient.EXPECT().GetUser(gomock.Any(), &pb.GetUserRequest{Id: mockUserID}).Return(user, nil) integration := test.BuildIntegrationForGRPCRequest(10, "SmartCar") @@ -240,7 +239,7 @@ func (s *SyntheticDevicesControllerTestSuite) TestGetSyntheticDeviceMintingPaylo email := "some@email.com" eth := addr.Hex() - user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) + user := test.BuildGetUserGRPC(mockUserID, &email, ð, &pb.UserReferrer{}) s.userClient.EXPECT().GetUser(gomock.Any(), &pb.GetUserRequest{Id: mockUserID}).Return(user, nil) integration := test.BuildIntegrationForGRPCRequest(10, "SmartCar") @@ -268,7 +267,7 @@ func (s *SyntheticDevicesControllerTestSuite) Test_MintSyntheticDeviceSmartcar() // addr := common.HexToAddress(userEthAddress) deviceEthAddr := common.HexToAddress("11") - user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) + user := test.BuildGetUserGRPC(mockUserID, &email, ð, &pb.UserReferrer{}) s.userClient.EXPECT().GetUser(gomock.Any(), &pb.GetUserRequest{Id: mockUserID}).Return(user, nil) integration := test.BuildIntegrationForGRPCRequest(1, "SmartCar") @@ -371,7 +370,7 @@ func (s *SyntheticDevicesControllerTestSuite) TestSignSyntheticDeviceMintingPayl email := "some@email.com" eth := addr.Hex() - user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) + user := test.BuildGetUserGRPC(mockUserID, &email, ð, &pb.UserReferrer{}) s.userClient.EXPECT().GetUser(gomock.Any(), &pb.GetUserRequest{Id: mockUserID}).Return(user, nil) integration := test.BuildIntegrationForGRPCRequest(10, "SmartCar") @@ -405,7 +404,7 @@ func (s *SyntheticDevicesControllerTestSuite) TestSignSyntheticDeviceMintingPayl // email := "some@email.com" // eth := userEthAddress - // user := test.BuildGetUserGRPC(mockUserID, &email, ð, &users.UserReferrer{}) + // user := test.BuildGetUserGRPC(mockUserID, &email, ð, &pb.UserReferrer{}) // s.userClient.EXPECT().GetUser(gomock.Any(), gomock.Any()).Return(user, nil) // scInt := &ddgrpc.Integration{