Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mint vehicle and pair AD together #72

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions abis/DimoRegistry.json
Original file line number Diff line number Diff line change
Expand Up @@ -2591,6 +2591,63 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "uint256",
"name": "manufacturerNodeVehicle",
"type": "uint256"
},
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"components": [
{
"internalType": "string",
"name": "attribute",
"type": "string"
},
{
"internalType": "string",
"name": "info",
"type": "string"
}
],
"internalType": "struct AttributeInfoPair[]",
"name": "attrInfoPairsVehicle",
"type": "tuple[]"
},
{
"internalType": "uint256",
"name": "aftermarketDeviceNode",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "vehicleOwnerSig",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "aftermarketDeviceSig",
"type": "bytes"
}
],
"internalType": "struct MintVehicleAndAdInput",
"name": "data",
"type": "tuple"
}
],
"name": "mintVehicleAndAdSign",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down
157 changes: 138 additions & 19 deletions contracts/implementations/MultipleMinter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import "../libraries/NodesStorage.sol";
import "../libraries/nodes/ManufacturerStorage.sol";
import "../libraries/nodes/IntegrationStorage.sol";
import "../libraries/nodes/VehicleStorage.sol";
import "../libraries/nodes/AftermarketDeviceStorage.sol";
import "../libraries/nodes/SyntheticDeviceStorage.sol";
import "../libraries/MapperStorage.sol";

Expand All @@ -24,9 +25,126 @@ contract MultipleMinter is
VehicleInternal,
SyntheticDeviceInternal
{
bytes32 private constant MINT_VEHICLE_AD_TYPEHASH =
keccak256("MintVehicleAndAdSign(uint256 aftermarketDeviceNode)");
bytes32 private constant MINT_VEHICLE_SD_TYPEHASH =
keccak256("MintVehicleAndSdSign(uint256 integrationNode)");

event AftermarketDeviceClaimed(
uint256 aftermarketDeviceNode,
address indexed owner
);
event AftermarketDevicePaired(
uint256 aftermarketDeviceNode,
uint256 vehicleNode,
address indexed owner
);

/**
* @notice Mints a vehicle, claim and pairs an aftermarket device through a metatransaction
* The vehicle owner signs a typed structured (EIP-712) message in advance and submits to be verified
* @dev Caller must have the admin role
* @param data Input data with the following fields:
* manufacturerNodeVehicle -> Parent manufacturer node id of the vehicle
* owner -> The new nodes owner
* attrInfoPairsVehicle -> List of attribute-info pairs to be added of the vehicle
* aftermarketDeviceNode -> The aftermarket device node ID to be claimed and paired
* vehicleOwnerSig -> Vehicle owner signature hash
* aftermarketDeviceSig -> Aftermarket Device's signature hash
*/
function mintVehicleAndAdSign(MintVehicleAndAdInput calldata data)
external
onlyRole(DEFAULT_ADMIN_ROLE)
{
NodesStorage.Storage storage ns = NodesStorage.getStorage();
MapperStorage.Storage storage ms = MapperStorage.getStorage();
AftermarketDeviceStorage.Storage storage ads = AftermarketDeviceStorage
.getStorage();

address vehicleIdProxyAddress = VehicleStorage
.getStorage()
.idProxyAddress;
address adIdProxyAddress = ads.idProxyAddress;
uint256 aftermarketDeviceNode = data.aftermarketDeviceNode;
address owner = data.owner;

if (
!INFT(ManufacturerStorage.getStorage().idProxyAddress).exists(
data.manufacturerNodeVehicle
)
) revert InvalidParentNode(data.manufacturerNodeVehicle);
if (!INFT(adIdProxyAddress).exists(aftermarketDeviceNode))
revert InvalidNode(adIdProxyAddress, aftermarketDeviceNode);
if (ads.deviceClaimed[aftermarketDeviceNode])
revert DeviceAlreadyClaimed(aftermarketDeviceNode);

bytes32 message = keccak256(
abi.encode(MINT_VEHICLE_AD_TYPEHASH, aftermarketDeviceNode)
);

if (
!Eip712CheckerInternal._verifySignature(
ads.nodeIdToDeviceAddress[aftermarketDeviceNode],
message,
data.aftermarketDeviceSig
)
) revert InvalidAdSignature();

uint256 newTokenIdVehicle = INFT(vehicleIdProxyAddress).safeMint(owner);

emit VehicleNodeMinted(
data.manufacturerNodeVehicle,
newTokenIdVehicle,
owner
);

(bytes32 attributesHash, bytes32 infosHash) = _setInfosHash(
newTokenIdVehicle,
data.attrInfoPairsVehicle
);

message = keccak256(
abi.encode(
MINT_VEHICLE_TYPEHASH,
data.manufacturerNodeVehicle,
owner,
attributesHash,
infosHash
)
);

if (
!Eip712CheckerInternal._verifySignature(
owner,
message,
data.vehicleOwnerSig
)
) revert InvalidOwnerSignature();

ads.deviceClaimed[aftermarketDeviceNode] = true;
INFT(adIdProxyAddress).safeTransferFrom(
INFT(adIdProxyAddress).ownerOf(aftermarketDeviceNode),
owner,
aftermarketDeviceNode
);

emit AftermarketDeviceClaimed(aftermarketDeviceNode, owner);

ns.nodes[vehicleIdProxyAddress][newTokenIdVehicle].parentNode = data
.manufacturerNodeVehicle;

ms.links[vehicleIdProxyAddress][
newTokenIdVehicle
] = aftermarketDeviceNode;
ms.links[adIdProxyAddress][aftermarketDeviceNode] = newTokenIdVehicle;

emit AftermarketDevicePaired(
aftermarketDeviceNode,
newTokenIdVehicle,
owner
);
}

/**
* @notice Mints and pairs a vehicle and a synthetic device through a metatransaction
* The vehicle owner signs a typed structured (EIP-712) message in advance and submits to be verified
Expand Down Expand Up @@ -54,6 +172,7 @@ contract MultipleMinter is
.getStorage()
.idProxyAddress;
address sdIdProxyAddress = sds.idProxyAddress;
address syntheticDeviceAddr = data.syntheticDeviceAddr;

if (
!INFT(IntegrationStorage.getStorage().idProxyAddress).exists(
Expand All @@ -65,16 +184,16 @@ contract MultipleMinter is
data.manufacturerNode
)
) revert InvalidParentNode(data.manufacturerNode);
if (sds.deviceAddressToNodeId[data.syntheticDeviceAddr] != 0)
revert DeviceAlreadyRegistered(data.syntheticDeviceAddr);
if (sds.deviceAddressToNodeId[syntheticDeviceAddr] != 0)
revert DeviceAlreadyRegistered(syntheticDeviceAddr);

bytes32 message = keccak256(
abi.encode(MINT_VEHICLE_SD_TYPEHASH, data.integrationNode)
);

if (
!Eip712CheckerInternal._verifySignature(
data.syntheticDeviceAddr,
syntheticDeviceAddr,
message,
data.syntheticDeviceSig
)
Expand All @@ -85,6 +204,20 @@ contract MultipleMinter is
);
uint256 newTokenIdDevice = INFT(sdIdProxyAddress).safeMint(data.owner);

emit VehicleNodeMinted(
data.manufacturerNode,
newTokenIdVehicle,
data.owner
);

emit SyntheticDeviceNodeMinted(
data.integrationNode,
newTokenIdDevice,
newTokenIdVehicle,
syntheticDeviceAddr,
data.owner
);

(bytes32 attributesHash, bytes32 infosHash) = _setInfosHash(
newTokenIdVehicle,
data.attrInfoPairsVehicle
Expand Down Expand Up @@ -121,24 +254,10 @@ contract MultipleMinter is
newTokenIdDevice
] = newTokenIdVehicle;

sds.deviceAddressToNodeId[data.syntheticDeviceAddr] = newTokenIdDevice;
sds.nodeIdToDeviceAddress[newTokenIdDevice] = data.syntheticDeviceAddr;
sds.deviceAddressToNodeId[syntheticDeviceAddr] = newTokenIdDevice;
sds.nodeIdToDeviceAddress[newTokenIdDevice] = syntheticDeviceAddr;

if (data.attrInfoPairsDevice.length > 0)
_setInfos(newTokenIdDevice, data.attrInfoPairsDevice);

emit VehicleNodeMinted(
data.manufacturerNode,
newTokenIdVehicle,
data.owner
);

emit SyntheticDeviceNodeMinted(
data.integrationNode,
newTokenIdDevice,
newTokenIdVehicle,
data.syntheticDeviceAddr,
data.owner
);
}
}
10 changes: 4 additions & 6 deletions contracts/implementations/nodes/AftermarketDevice.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import "@solidstate/contracts/access/access_control/AccessControlInternal.sol";

error RegistryNotApproved();
error DeviceAlreadyRegistered(address addr);
error DeviceAlreadyClaimed(uint256 id);
error InvalidAdSignature();
error AdNotClaimed(uint256 id);
error AdPaired(uint256 id);
error AdNotPaired(uint256 id);
Expand Down Expand Up @@ -223,7 +221,7 @@ contract AftermarketDevice is
owner = adOwnerPair[i].owner;

if (ads.deviceClaimed[aftermarketDeviceNode])
revert DeviceAlreadyClaimed(aftermarketDeviceNode);
revert Errors.DeviceAlreadyClaimed(aftermarketDeviceNode);

ads.deviceClaimed[aftermarketDeviceNode] = true;
adIdProxy.safeTransferFrom(
Expand Down Expand Up @@ -265,7 +263,7 @@ contract AftermarketDevice is
if (!INFT(adIdProxy).exists(aftermarketDeviceNode))
revert Errors.InvalidNode(adIdProxy, aftermarketDeviceNode);
if (ads.deviceClaimed[aftermarketDeviceNode])
revert DeviceAlreadyClaimed(aftermarketDeviceNode);
revert Errors.DeviceAlreadyClaimed(aftermarketDeviceNode);
if (!Eip712CheckerInternal._verifySignature(owner, message, ownerSig))
revert Errors.InvalidOwnerSignature();
if (
Expand All @@ -274,7 +272,7 @@ contract AftermarketDevice is
message,
aftermarketDeviceSig
)
) revert InvalidAdSignature();
) revert Errors.InvalidAdSignature();

ads.deviceClaimed[aftermarketDeviceNode] = true;
INFT(adIdProxy).safeTransferFrom(
Expand Down Expand Up @@ -333,7 +331,7 @@ contract AftermarketDevice is
message,
aftermarketDeviceSig
)
) revert InvalidAdSignature();
) revert Errors.InvalidAdSignature();

if (
!Eip712CheckerInternal._verifySignature(
Expand Down
2 changes: 2 additions & 0 deletions contracts/shared/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ error InvalidParentNodeOwner(uint256 id, address addr);
error InvalidNode(address proxy, uint256 id);
error VehiclePaired(uint256 id);
error VehicleNotPaired(uint256 id);
error DeviceAlreadyClaimed(uint256 id);

// Signature
error InvalidSigner();
error InvalidOwnerSignature();
error InvalidAdSignature();
9 changes: 9 additions & 0 deletions contracts/shared/Types.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ struct MintSyntheticDeviceInput {
AttributeInfoPair[] attrInfoPairs;
}

struct MintVehicleAndAdInput {
uint256 manufacturerNodeVehicle;
address owner;
AttributeInfoPair[] attrInfoPairsVehicle;
uint256 aftermarketDeviceNode;
bytes vehicleOwnerSig;
bytes aftermarketDeviceSig;
}

struct MintVehicleAndSdInput {
uint256 manufacturerNode;
address owner;
Expand Down
Loading