From 27a99dc19af18c82f782b1a2f70df864386ea1af Mon Sep 17 00:00:00 2001 From: shum Date: Wed, 21 Oct 2026 22:07:25 +0000 Subject: [PATCH] store: one link per key and resolver digests --- .../src/StoreService/Names/Registration.hs | 38 +++++++++++++++---- .../StoreService/NameRegistrationTests.hs | 10 ++--- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/apps/simplex-store-service/src/StoreService/Names/Registration.hs b/apps/simplex-store-service/src/StoreService/Names/Registration.hs index e29abb8d7a..ff34551843 100644 --- a/apps/simplex-store-service/src/StoreService/Names/Registration.hs +++ b/apps/simplex-store-service/src/StoreService/Names/Registration.hs @@ -5,20 +5,24 @@ module StoreService.Names.Registration ( Registration (..), RegisterIntent (..), sponsorDomain, + resolverDomain, makeCommitment, commitCalldata, registerWithCreditCalldata, registerIntentDigest, verifyRegisterIntent, + setTextDigest, + clearRecordsDigest, ) where import Control.Monad (unless, when) import Control.Monad.Except (ExceptT (..), runExceptT, throwError) +import Crypto.Number.Serialize (os2ip) import Data.ByteString (ByteString) import qualified Data.ByteString as B +import Data.Maybe (catMaybes) import Data.Text (Text) -import qualified Data.Text as T import Data.Text.Encoding (encodeUtf8) import Data.Word (Word64) import Simplex.Messaging.Crypto (keccak256) @@ -36,8 +40,8 @@ data Registration = Registration rDuration :: Word64, rSecret :: ByteString, rResolver :: Address, - rContactLinks :: [Text], - rChannelLinks :: [Text] + rContactLink :: Maybe Text, + rChannelLink :: Maybe Text } data RegisterIntent = RegisterIntent @@ -50,6 +54,9 @@ data RegisterIntent = RegisterIntent sponsorDomain :: Word64 -> Address -> Eip712Domain sponsorDomain edChainId edVerifyingContract = Eip712Domain {edName = "SimplexSponsor", edVersion = "1", edChainId, edVerifyingContract} +resolverDomain :: Word64 -> Address -> Eip712Domain +resolverDomain edChainId edVerifyingContract = Eip712Domain {edName = "SimplexResolver", edVersion = "1", edChainId, edVerifyingContract} + makeCommitment :: Registration -> ByteString makeCommitment r = keccak256 $ abiTuple [Dynamic $ registrationTuple r] @@ -87,6 +94,23 @@ verifyRegisterIntent domain now RegisterIntent {riRegistration = r@Registration signer <- ExceptT $ recoverAddress riSignature $ registerIntentDigest domain r riNonce riDeadline unless (signer == rOwner) $ throwError "intent is not signed by the owner" +setTextDigest :: Eip712Domain -> ByteString -> Text -> Text -> Word64 -> Word64 -> ByteString +setTextDigest domain node key value nonce deadline = + hashTypedData + domain + "SetText(bytes32 node,string key,string value,uint256 nonce,uint256 deadline)" + [bytes32 node, VBytes $ encodeUtf8 key, VBytes $ encodeUtf8 value, VUint $ fromIntegral nonce, VUint $ fromIntegral deadline] + +clearRecordsDigest :: Eip712Domain -> ByteString -> Word64 -> Word64 -> ByteString +clearRecordsDigest domain node nonce deadline = + hashTypedData + domain + "ClearRecords(bytes32 node,uint256 nonce,uint256 deadline)" + [bytes32 node, VUint $ fromIntegral nonce, VUint $ fromIntegral deadline] + +bytes32 :: ByteString -> Eip712Value +bytes32 = VUint . fromInteger . os2ip + registrationTuple :: Registration -> ByteString registrationTuple r@Registration {rLabel, rOwner, rDuration, rSecret, rResolver} = abiTuple @@ -104,12 +128,12 @@ registrationTuple r@Registration {rLabel, rOwner, rDuration, rSecret, rResolver} referrer = B.replicate 32 0 recordCalls :: Registration -> [ByteString] -recordCalls Registration {rLabel, rTLD, rContactLinks, rChannelLinks} = - [setText key ls | (key, ls) <- [("simplex.contact", rContactLinks), ("simplex.channel", rChannelLinks)], not (null ls)] +recordCalls Registration {rLabel, rTLD, rContactLink, rChannelLink} = + catMaybes [setText "simplex.contact" <$> rContactLink, setText "simplex.channel" <$> rChannelLink] where - setText key ls = + setText key link = selector "setText(bytes32,string,string)" - <> abiTuple [Static node, Dynamic $ abiBytes key, Dynamic $ abiBytes $ encodeUtf8 $ T.intercalate ";" ls] + <> abiTuple [Static node, Dynamic $ abiBytes key, Dynamic $ abiBytes $ encodeUtf8 link] node = namehash rTLD rLabel namehash :: SimplexTLD -> Text -> ByteString diff --git a/tests/Bots/StoreService/NameRegistrationTests.hs b/tests/Bots/StoreService/NameRegistrationTests.hs index fa5e096c4d..2b652cb9e5 100644 --- a/tests/Bots/StoreService/NameRegistrationTests.hs +++ b/tests/Bots/StoreService/NameRegistrationTests.hs @@ -43,17 +43,17 @@ testRegisterCalldataWithRecords :: TVar ChaChaDRG -> IO () testRegisterCalldataWithRecords g = do intent <- knownIntent g knownRegistration toHex (registerWithCreditCalldata intent) - `shouldBe` "c4bd2ab50000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f4865700000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000001000000000000000000000000009858effd232b4033e47d90003d41ec34ecaeda940000000000000000000000000000000000000000000000000000000003c2670011111111111111111111111111111111111111111111111111111111111111110000000000000000000000002279b7a0a67db372996a5fab50d91eaa73d2ebe6000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000762616b657279310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000e410f13a8c58c186cadf476923d25ea4950487d1aaf21906ba5574c87f5b9435b61b994370000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000f73696d706c65782e636f6e746163740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002068747470733a2f2f736d702e73696d706c65782e696d2f6123636f6e7461637400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010410f13a8c58c186cadf476923d25ea4950487d1aaf21906ba5574c87f5b9435b61b994370000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000f73696d706c65782e6368616e6e656c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003b68747470733a2f2f736d70312e73696d706c65782e696d2f63236f6e653b68747470733a2f2f736d70322e73696d706c65782e696d2f632374776f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000417caacde8c40eab73721947d6d811746266da03d0cb50da2e7efea9c7c926b7124cc612132c7c5e178fcf75afcc709994ca96b16ef30d9763ab22102192e9ac441b00000000000000000000000000000000000000000000000000000000000000" + `shouldBe` "c4bd2ab50000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f4865700000000000000000000000000000000000000000000000000000000000000046000000000000000000000000000000000000000000000000000000000000001000000000000000000000000009858effd232b4033e47d90003d41ec34ecaeda940000000000000000000000000000000000000000000000000000000003c2670011111111111111111111111111111111111111111111111111111111111111110000000000000000000000002279b7a0a67db372996a5fab50d91eaa73d2ebe6000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000762616b657279310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000e410f13a8c58c186cadf476923d25ea4950487d1aaf21906ba5574c87f5b9435b61b994370000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000f73696d706c65782e636f6e746163740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002068747470733a2f2f736d702e73696d706c65782e696d2f6123636f6e746163740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e410f13a8c58c186cadf476923d25ea4950487d1aaf21906ba5574c87f5b9435b61b994370000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000f73696d706c65782e6368616e6e656c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d68747470733a2f2f736d70312e73696d706c65782e696d2f63236f6e65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041f310b273d0e0ab0975a66d383fe818a5ec3474fcd922dbf3fe70094a3c0ceae86559b13ea0728a330613c6fe236a89a026daf345dcc8c0616e9eda2c69cbeb091b00000000000000000000000000000000000000000000000000000000000000" testRegisterCalldataWithoutRecords :: TVar ChaChaDRG -> IO () testRegisterCalldataWithoutRecords g = do - intent <- knownIntent g knownRegistration {rContactLinks = [], rChannelLinks = []} + intent <- knownIntent g knownRegistration {rContactLink = Nothing, rChannelLink = Nothing} toHex (registerWithCreditCalldata intent) `shouldBe` "c4bd2ab50000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f486570000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001000000000000000000000000009858effd232b4033e47d90003d41ec34ecaeda940000000000000000000000000000000000000000000000000000000003c2670011111111111111111111111111111111111111111111111111111111111111110000000000000000000000002279b7a0a67db372996a5fab50d91eaa73d2ebe6000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000762616b6572793100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000411d0b3a477c99fbcadada2937b71127bf6da202f5cd25856649829653d8cf6a8c0ce0afb8505e398e23b3b01fcb3b17ffcf82d8ba6d24e9b854506894b2864ecf1c00000000000000000000000000000000000000000000000000000000000000" testCommitCalldata :: IO () testCommitCalldata = - toHex (commitCalldata $ makeCommitment knownRegistration) `shouldBe` "f14fcbc843aeb4617085160f4dc7ad495d1119f39bca441276b1990123fd3ecb8a40a360" + toHex (commitCalldata $ makeCommitment knownRegistration) `shouldBe` "f14fcbc8810f0645b8d9839e3744bb956f9da4fa12bb51ec97459e08739c576a36cba0df" testVerifyOtherSigner :: TVar ChaChaDRG -> IO () testVerifyOtherSigner g = do @@ -102,8 +102,8 @@ knownRegistration = rDuration = 63072000, rSecret = B.replicate 32 0x11, rResolver = address "0x2279b7a0a67db372996a5fab50d91eaa73d2ebe6", - rContactLinks = ["https://smp.simplex.im/a#contact"], - rChannelLinks = ["https://smp1.simplex.im/c#one", "https://smp2.simplex.im/c#two"] + rContactLink = Just "https://smp.simplex.im/a#contact", + rChannelLink = Just "https://smp1.simplex.im/c#one" } knownIntent :: TVar ChaChaDRG -> Registration -> IO RegisterIntent