Repository: onflow/fcl-js
Pull request #1028 (2022-02-14 20:56:27)

[fcl] - Update `WalletUtils` encoding for authn-signing and auth-verifying
### Update `WalletUtils` encoding for authn-signing and auth-verifying.

Encoding should leave all field that can exist as Buffers before RLP encoding as Buffers. This strategy will help maintain greater consistency with how these fields are treated when encoded in other areas of Flow.

```js
MESSAGE = 
  HEX(
    USER_DOMAIN_TAG, // Buffer, right padded to 32 bytes long
    RLP(
      APP_DOMAIN_TAG, // [Optional] Buffer, right padded to 32 bytes long
      ADDRESS,  // Buffer, left padded to 8 bytes long
      TIMESTAMP // Number
    )
  )
```

Addresses https://github.com/onflow/fcl-js/issues/1015


Patch:
diff --git a/packages/fcl/CHANGELOG.md b/packages/fcl/CHANGELOG.md
index 57db1a1d..aa9b3dc9 100644
--- a/packages/fcl/CHANGELOG.md
+++ b/packages/fcl/CHANGELOG.md
@@ -1,5 +1,19 @@
 ## Unreleased
 
+- 2022-02-14 -- [gregsantos](https://github.com/gregsantos): Update `WalletUtils` encoding for authn-signing and auth-verifying.
+Encoding should leave all field that can exist as Buffers before RLP encoding as Buffers. This strategy will help maintain greater consistency with how these fields are treated when encoded in other areas of Flow.
+
+```js
+MESSAGE = 
+  HEX(
+    USER_DOMAIN_TAG, // Buffer, right padded to 32 bytes long
+    RLP(
+      APP_DOMAIN_TAG, // [Optional] Buffer, right padded to 32 bytes long
+      ADDRESS,  // Buffer, left padded to 8 bytes long
+      TIMESTAMP // Number
+    )
+  )
+```
 - 2022-02-14 -- [chasefleming](https://github.com/chasefleming): Remove experimental redir warning from previous alpha build.
 - 2022-02-08 -- [gregsantos](https://github.com/gregsantos): Update extension strategy to add support for `EXT/RPC` service method
 
diff --git a/packages/fcl/src/wallet-utils/encode-provable-authn-signing.js b/packages/fcl/src/wallet-utils/encode-provable-authn-signing.js
index 003e0eb2..533363da 100644
--- a/packages/fcl/src/wallet-utils/encode-provable-authn-signing.js
+++ b/packages/fcl/src/wallet-utils/encode-provable-authn-signing.js
@@ -1,20 +1,46 @@
-import {withPrefix} from "@onflow/util-address"
+import {sansPrefix} from "@onflow/util-address"
 import {invariant} from "@onflow/util-invariant"
-import {encode} from '@onflow/rlp'
+import {encode as rlpEncode} from "@onflow/rlp"
 
 const rightPaddedHexBuffer = (value, pad) =>
   Buffer.from(value.padEnd(pad * 2, 0), "hex")
 
-export const encodeMessageForProvableAuthnSigning = (address, timestamp, appDomainTag = "") => {
-    invariant(address, "Encode Message From Provable Authn Error: address must be defined")
-    invariant(timestamp, "Encode Message From Provable Authn Error: timestamp must be defined")
+const leftPaddedHexBuffer = (value, pad) =>
+  Buffer.from(value.padStart(pad * 2, 0), "hex")
 
-    const USER_DOMAIN_TAG = rightPaddedHexBuffer(Buffer.from("FLOW-V0.0-user").toString("hex"), 32).toString("hex")
-    const APP_DOMAIN_TAG = rightPaddedHexBuffer(Buffer.from(appDomainTag).toString("hex"), 32).toString("hex")
+const addressBuffer = addr => leftPaddedHexBuffer(addr, 8)
 
-    return USER_DOMAIN_TAG + (appDomainTag ? 
-        encode([APP_DOMAIN_TAG, withPrefix(address), timestamp]).toString("hex")
-        :
-        encode([withPrefix(address), timestamp]).toString("hex")
-    )
+export const encodeMessageForProvableAuthnSigning = (
+  address,
+  timestamp,
+  appDomainTag = ""
+) => {
+  invariant(
+    address,
+    "Encode Message For Provable Authn Error: address must be defined"
+  )
+  invariant(
+    timestamp,
+    "Encode Message For Provable Authn Error: timestamp must be defined"
+  )
+
+  const USER_DOMAIN_TAG = rightPaddedHexBuffer(
+    Buffer.from("FLOW-V0.0-user").toString("hex"),
+    32
+  )
+
+  const APP_DOMAIN_TAG = appDomainTag
+    ? rightPaddedHexBuffer(Buffer.from(appDomainTag).toString("hex"), 32)
+    : null
+
+  return Buffer.concat([
+    USER_DOMAIN_TAG,
+    appDomainTag
+      ? rlpEncode([
+          APP_DOMAIN_TAG,
+          addressBuffer(sansPrefix(address)),
+          timestamp,
+        ])
+      : rlpEncode([addressBuffer(sansPrefix(address)), timestamp]),
+  ]).toString("hex")
 }
diff --git a/packages/fcl/src/wallet-utils/encode-provable-authn-verifying.js b/packages/fcl/src/wallet-utils/encode-provable-authn-verifying.js
index 1c5957d7..e6f69793 100644
--- a/packages/fcl/src/wallet-utils/encode-provable-authn-verifying.js
+++ b/packages/fcl/src/wallet-utils/encode-provable-authn-verifying.js
@@ -1,19 +1,40 @@
-import {withPrefix} from "@onflow/util-address"
+import {sansPrefix} from "@onflow/util-address"
 import {invariant} from "@onflow/util-invariant"
-import {encode} from '@onflow/rlp'
+import {encode as rlpEncode} from "@onflow/rlp"
 
 const rightPaddedHexBuffer = (value, pad) =>
   Buffer.from(value.padEnd(pad * 2, 0), "hex")
 
-export const encodeMessageForProvableAuthnVerifying = (address, timestamp, appDomainTag = "") => {
-    invariant(address, "Encode Message From Provable Authn Error: address must be defined")
-    invariant(timestamp, "Encode Message From Provable Authn Error: timestamp must be defined")
+const leftPaddedHexBuffer = (value, pad) =>
+  Buffer.from(value.padStart(pad * 2, 0), "hex")
 
-    const APP_DOMAIN_TAG = appDomainTag ? rightPaddedHexBuffer(Buffer.from(appDomainTag).toString("hex"), 32).toString("hex") : null
+const addressBuffer = addr => leftPaddedHexBuffer(addr, 8)
 
-    return (appDomainTag ? 
-      encode([APP_DOMAIN_TAG, withPrefix(address), timestamp]).toString("hex")
-      :
-      encode([withPrefix(address), timestamp]).toString("hex")
-    )
+export const encodeMessageForProvableAuthnVerifying = (
+  address,
+  timestamp,
+  appDomainTag = ""
+) => {
+  invariant(
+    address,
+    "Encode Message For Provable Authn Error: address must be defined"
+  )
+  invariant(
+    timestamp,
+    "Encode Message For Provable Authn Error: timestamp must be defined"
+  )
+
+  const APP_DOMAIN_TAG = appDomainTag
+    ? rightPaddedHexBuffer(Buffer.from(appDomainTag).toString("hex"), 32)
+    : null
+
+  return (
+    appDomainTag
+      ? rlpEncode([
+          APP_DOMAIN_TAG,
+          addressBuffer(sansPrefix(address)),
+          timestamp,
+        ])
+      : rlpEncode([addressBuffer(sansPrefix(address)), timestamp])
+  ).toString("hex")
 }


Test patch:
diff --git a/packages/fcl/src/wallet-utils/__snapshots__/encode-provable-authn-signing.test.js.snap b/packages/fcl/src/wallet-utils/__snapshots__/encode-provable-authn-signing.test.js.snap
index 223f1b0f..7d6f6432 100644
--- a/packages/fcl/src/wallet-utils/__snapshots__/encode-provable-authn-signing.test.js.snap
+++ b/packages/fcl/src/wallet-utils/__snapshots__/encode-provable-authn-signing.test.js.snap
@@ -1,5 +1,5 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`encode provable authn encode provable authn with appTag 1`] = `"464c4f572d56302e302d75736572000000000000000000000000000000000000f850b8403436346334663537326434613533326435333434346230303030303030303030303030303030303030303030303030303030303030303030303030303030303086abc123def45686017c05815137"`;
+exports[`encode provable authn encode provable authn with appTag 1`] = `"464c4f572d56302e302d75736572000000000000000000000000000000000000f1a0464c4f572d4a532d53444b000000000000000000000000000000000000000000880000abc123def45686017c05815137"`;
 
-exports[`encode provable authn encode provable authn without appTag 1`] = `"464c4f572d56302e302d75736572000000000000000000000000000000000000ce86abc123def45686017c05815137"`;
+exports[`encode provable authn encode provable authn without appTag 1`] = `"464c4f572d56302e302d75736572000000000000000000000000000000000000d0880000abc123def45686017c05815137"`;
diff --git a/packages/fcl/src/wallet-utils/__snapshots__/encode-provable-authn-verifying.test.js.snap b/packages/fcl/src/wallet-utils/__snapshots__/encode-provable-authn-verifying.test.js.snap
index 12b82126..27603f68 100644
--- a/packages/fcl/src/wallet-utils/__snapshots__/encode-provable-authn-verifying.test.js.snap
+++ b/packages/fcl/src/wallet-utils/__snapshots__/encode-provable-authn-verifying.test.js.snap
@@ -1,5 +1,5 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`encode provable authn encode provable authn with appTag 1`] = `"f850b8403436346334663537326434613533326435333434346230303030303030303030303030303030303030303030303030303030303030303030303030303030303086abc123def45686017c05815137"`;
+exports[`encode provable authn encode provable authn with appTag 1`] = `"f1a0464c4f572d4a532d53444b000000000000000000000000000000000000000000880000abc123def45686017c05815137"`;
 
-exports[`encode provable authn encode provable authn without appTag 1`] = `"ce86abc123def45686017c05815137"`;
+exports[`encode provable authn encode provable authn without appTag 1`] = `"d0880000abc123def45686017c05815137"`;