diff --git a/compliant-reward-distribution/frontend/package.json b/compliant-reward-distribution/frontend/package.json
index 83719471..29bc6fe9 100644
--- a/compliant-reward-distribution/frontend/package.json
+++ b/compliant-reward-distribution/frontend/package.json
@@ -18,6 +18,7 @@
"@concordium/web-sdk": "^7.3.2",
"@types/sha256": "^0.2.2",
"bootstrap": "^5.3.3",
+ "buffer": "^6.0.3",
"json-bigint": "^1.0.0",
"moment": "^2.30.1",
"react": "^18.2.0",
diff --git a/compliant-reward-distribution/frontend/src/App.tsx b/compliant-reward-distribution/frontend/src/App.tsx
index e95c6166..078c1a11 100644
--- a/compliant-reward-distribution/frontend/src/App.tsx
+++ b/compliant-reward-distribution/frontend/src/App.tsx
@@ -78,7 +78,10 @@ export const App = () => {
element={}
/>
- } />
+ }
+ />
} />
diff --git a/compliant-reward-distribution/frontend/src/components/Admin.tsx b/compliant-reward-distribution/frontend/src/components/Admin.tsx
index 915d1676..75649f4a 100644
--- a/compliant-reward-distribution/frontend/src/components/Admin.tsx
+++ b/compliant-reward-distribution/frontend/src/components/Admin.tsx
@@ -2,20 +2,22 @@ import { ConcordiumGRPCClient } from '@concordium/web-sdk';
import { AdminGetAccountData } from './AdminGetAccountData';
import { AdminGetPendingApprovals } from './AdminGetPendingApprovals';
import { AdminSetClaimed } from './AdminSetClaimed';
+import { WalletProvider } from '../../wallet-connection';
interface Props {
accountAddress: string | undefined;
grpcClient: ConcordiumGRPCClient | undefined;
+ provider: WalletProvider | undefined;
}
export function Admin(props: Props) {
- const { accountAddress, grpcClient } = props;
+ const { accountAddress, grpcClient, provider } = props;
return (
);
}
diff --git a/compliant-reward-distribution/frontend/src/components/AdminGetAccountData.tsx b/compliant-reward-distribution/frontend/src/components/AdminGetAccountData.tsx
index f5488f6d..23f0d80e 100644
--- a/compliant-reward-distribution/frontend/src/components/AdminGetAccountData.tsx
+++ b/compliant-reward-distribution/frontend/src/components/AdminGetAccountData.tsx
@@ -2,17 +2,19 @@ import { useState } from 'react';
import { useForm, useWatch } from 'react-hook-form';
import { Alert, Button, Form } from 'react-bootstrap';
-import { getAccountData, getARecentBlockHash, validateAccountAddress } from '../utils';
+import { getAccountData, getARecentBlockHash, requestSignature, validateAccountAddress } from '../utils';
import { ConcordiumGRPCClient } from '@concordium/web-sdk';
import JSONbig from 'json-bigint';
+import { WalletProvider } from '../../wallet-connection';
interface Props {
signer: string | undefined;
+ provider: WalletProvider | undefined;
grpcClient: ConcordiumGRPCClient | undefined;
}
export function AdminGetAccountData(props: Props) {
- const { signer, grpcClient } = props;
+ const { provider, signer, grpcClient } = props;
interface FormType {
address: string;
@@ -37,15 +39,10 @@ export function AdminGetAccountData(props: Props) {
}
const [recentBlockHash, recentBlockHeight] = await getARecentBlockHash(grpcClient);
- console.log(recentBlockHash);
- // TODO: add signature generation
+ const schema = 'FAADAAAADgAAAGNvbnRleHRfc3RyaW5nFgIHAAAAbWVzc2FnZQsKAAAAYmxvY2tfaGFzaBYC';
+ const signature = await requestSignature(recentBlockHash, schema, address, signer, provider);
- const data = await getAccountData(
- signer,
- address,
- 'c4bb83e7d7a9e6fe7a1b5f527174f7e368db9385b25fce0f4e4b7190781e57b5de6ad65a7481f1038f859d4c4ba8c07ed649b84f9e3c17e2bbdb87cf527cd602',
- recentBlockHeight,
- );
+ const data = await getAccountData(signer, address, signature, recentBlockHeight);
setAccountData(JSONbig.stringify(data));
} catch (error) {
setError((error as Error).message);
diff --git a/compliant-reward-distribution/frontend/src/components/AdminGetPendingApprovals.tsx b/compliant-reward-distribution/frontend/src/components/AdminGetPendingApprovals.tsx
index d7a8489c..9400c7b1 100644
--- a/compliant-reward-distribution/frontend/src/components/AdminGetPendingApprovals.tsx
+++ b/compliant-reward-distribution/frontend/src/components/AdminGetPendingApprovals.tsx
@@ -3,16 +3,18 @@ import { useForm } from 'react-hook-form';
import { Alert, Button, Form } from 'react-bootstrap';
import { ConcordiumGRPCClient } from '@concordium/web-sdk';
-import { getARecentBlockHash, getPendingApprovals } from '../utils';
+import { getARecentBlockHash, getPendingApprovals, requestSignature } from '../utils';
import JSONbig from 'json-bigint';
+import { WalletProvider } from '../../wallet-connection';
interface Props {
+ provider: WalletProvider | undefined;
signer: string | undefined;
grpcClient: ConcordiumGRPCClient | undefined;
}
export function AdminGetPendingApprovals(props: Props) {
- const { signer, grpcClient } = props;
+ const { provider, signer, grpcClient } = props;
const { handleSubmit } = useForm<[]>({ mode: 'all' });
@@ -29,18 +31,14 @@ export function AdminGetPendingApprovals(props: Props) {
}
const [recentBlockHash, recentBlockHeight] = await getARecentBlockHash(grpcClient);
- console.log(recentBlockHash);
const limit = 5;
const offset = 0;
- // TODO: add signature generation
- const data = await getPendingApprovals(
- signer,
- 'c4bb83e7d7a9e6fe7a1b5f527174f7e368db9385b25fce0f4e4b7190781e57b5de6ad65a7481f1038f859d4c4ba8c07ed649b84f9e3c17e2bbdb87cf527cd602',
- recentBlockHeight,
- limit,
- offset,
- );
+ const schema =
+ 'FAADAAAADgAAAGNvbnRleHRfc3RyaW5nFgIHAAAAbWVzc2FnZRQAAgAAAAUAAABsaW1pdAQGAAAAb2Zmc2V0BAoAAABibG9ja19oYXNoFgI';
+ const signature = await requestSignature(recentBlockHash, schema, { limit, offset }, signer, provider);
+
+ const data = await getPendingApprovals(signer, signature, recentBlockHeight, limit, offset);
setPendingApprovals(JSONbig.stringify(data));
} catch (error) {
setError((error as Error).message);
diff --git a/compliant-reward-distribution/frontend/src/components/AdminSetClaimed.tsx b/compliant-reward-distribution/frontend/src/components/AdminSetClaimed.tsx
index aced57a0..1604b04c 100644
--- a/compliant-reward-distribution/frontend/src/components/AdminSetClaimed.tsx
+++ b/compliant-reward-distribution/frontend/src/components/AdminSetClaimed.tsx
@@ -2,16 +2,18 @@ import { useState } from 'react';
import { useForm, useWatch } from 'react-hook-form';
import { Alert, Button, Form } from 'react-bootstrap';
-import { getARecentBlockHash, setClaimed, validateAccountAddress } from '../utils';
+import { getARecentBlockHash, requestSignature, setClaimed, validateAccountAddress } from '../utils';
import { ConcordiumGRPCClient } from '@concordium/web-sdk';
+import { WalletProvider } from '../../wallet-connection';
interface Props {
+ provider: WalletProvider | undefined;
signer: string | undefined;
grpcClient: ConcordiumGRPCClient | undefined;
}
export function AdminSetClaimed(props: Props) {
- const { signer, grpcClient } = props;
+ const { provider, signer, grpcClient } = props;
interface FormType {
address: string;
@@ -34,15 +36,11 @@ export function AdminSetClaimed(props: Props) {
}
const [recentBlockHash, recentBlockHeight] = await getARecentBlockHash(grpcClient);
- console.log(recentBlockHash);
- // TODO: add signature generation
- await setClaimed(
- signer,
- 'c4bb83e7d7a9e6fe7a1b5f527174f7e368db9385b25fce0f4e4b7190781e57b5de6ad65a7481f1038f859d4c4ba8c07ed649b84f9e3c17e2bbdb87cf527cd602',
- recentBlockHeight,
- address,
- );
+ const schema = 'FAADAAAADgAAAGNvbnRleHRfc3RyaW5nFgIHAAAAbWVzc2FnZRACCwoAAABibG9ja19oYXNoFgI';
+ const signature = await requestSignature(recentBlockHash, schema, [address], signer, provider);
+
+ await setClaimed(signer, signature, recentBlockHeight, address);
} catch (error) {
setError((error as Error).message);
}
diff --git a/compliant-reward-distribution/frontend/src/components/TweetSubmission.tsx b/compliant-reward-distribution/frontend/src/components/TweetSubmission.tsx
index 061d8d36..b7875f51 100644
--- a/compliant-reward-distribution/frontend/src/components/TweetSubmission.tsx
+++ b/compliant-reward-distribution/frontend/src/components/TweetSubmission.tsx
@@ -2,11 +2,8 @@ import { useState } from 'react';
import { useForm, useWatch } from 'react-hook-form';
import { Alert, Button, Form } from 'react-bootstrap';
-import sha256 from 'sha256';
-
-import { getARecentBlockHash, submitTweet } from '../utils';
+import { getARecentBlockHash, requestSignature, submitTweet } from '../utils';
import { ConcordiumGRPCClient } from '@concordium/web-sdk';
-import { CONTEXT_STRING } from '../constants';
import { WalletProvider } from '../../wallet-connection';
interface Props {
@@ -40,24 +37,10 @@ export function TweetSubmission(props: Props) {
throw Error(`'signer' is undefined. Connect your wallet.`);
}
- if (!provider) {
- throw Error(`'provider' is undefined`);
- }
-
const [recentBlockHash, recentBlockHeight] = await getARecentBlockHash(grpcClient);
+ const schema = 'FAADAAAADgAAAGNvbnRleHRfc3RyaW5nFgIHAAAAbWVzc2FnZRYCCgAAAGJsb2NrX2hhc2gWAg';
- const encoder = new TextEncoder();
- const tweetBytes = encoder.encode(tweet);
-
- const digest = [recentBlockHash, CONTEXT_STRING, tweetBytes].flatMap((item) => Array.from(item));
-
- const messageHash = sha256(digest);
-
- const signatures = (await provider.signMessage(signer, messageHash))
- if (Object.keys(signatures).length !== 1 || Object.keys(signatures[0]).length !== 1) {
- throw Error(`Dapp only supports single singer accounts`);
- }
- const signature = signatures[0][0];
+ const signature = await requestSignature(recentBlockHash, schema, tweet, signer, provider);
await submitTweet(signer, signature, recentBlockHeight, tweet);
} catch (error) {
diff --git a/compliant-reward-distribution/frontend/src/components/ZkProofSubmission.tsx b/compliant-reward-distribution/frontend/src/components/ZkProofSubmission.tsx
index 11cdf94d..9b69d4c6 100644
--- a/compliant-reward-distribution/frontend/src/components/ZkProofSubmission.tsx
+++ b/compliant-reward-distribution/frontend/src/components/ZkProofSubmission.tsx
@@ -7,6 +7,7 @@ import { ConcordiumGRPCClient, CredentialStatement } from '@concordium/web-sdk';
import { getARecentBlockHash, getStatement, submitZkProof } from '../utils';
import { CONTEXT_STRING } from '../constants';
import sha256 from 'sha256';
+import { Buffer } from 'buffer';
interface Props {
accountAddress: string | undefined;
@@ -41,12 +42,12 @@ export function ZkProofSubmission(props: Props) {
}
if (!provider) {
- throw Error(`'provider' is undefined`);
+ throw Error(`'provider' is undefined. Connect your wallet.`);
}
const [recentBlockHash, recentBlockHeight] = await getARecentBlockHash(grpcClient);
- const digest = [recentBlockHash, CONTEXT_STRING];
+ const digest = [recentBlockHash, Buffer.from(CONTEXT_STRING)];
const challenge = sha256(digest.flatMap((item) => Array.from(item)));
const presentation = await provider.requestVerifiablePresentation(challenge, [zkStatement]);
diff --git a/compliant-reward-distribution/frontend/src/constants.ts b/compliant-reward-distribution/frontend/src/constants.ts
index 447f9de7..d1910421 100644
--- a/compliant-reward-distribution/frontend/src/constants.ts
+++ b/compliant-reward-distribution/frontend/src/constants.ts
@@ -20,14 +20,11 @@ export const NETWORK = CONFIG.network === 'mainnet' ? MAINNET : TESTNET;
export const CCD_SCAN_URL = NETWORK === MAINNET ? 'https://ccdscan.io' : 'https://testnet.ccdscan.io';
export const BACKEDN_BASE_URL = 'http://localhost:8080/';
-// The string "CONCORDIUM_COMPLIANT_REWARD_DISTRIBUTION_DAPP" in bytes is used
+// The string "CONCORDIUM_COMPLIANT_REWARD_DISTRIBUTION_DAPP" is used
// as context for signing messages and generating ZK proofs. The same account
// can be used in different Concordium services without the risk of re-playing
// signatures/zk-proofs across the different services due to this context string.
-export const CONTEXT_STRING = new Uint8Array([
- 67, 79, 78, 67, 79, 82, 68, 73, 85, 77, 95, 67, 79, 77, 80, 76, 73, 65, 78, 84, 95, 82, 69, 87, 65, 82, 68, 95, 68,
- 73, 83, 84, 82, 73, 66, 85, 84, 73, 79, 78, 95, 68, 65, 80, 80,
-]);
+export const CONTEXT_STRING = 'CONCORDIUM_COMPLIANT_REWARD_DISTRIBUTION_DAPP';
// Before submitting a transaction we simulate/dry-run the transaction to get an
// estimate of the energy needed for executing the transaction. In addition, we
@@ -50,6 +47,3 @@ export const walletConnectOpts: SignClientTypes.Options = {
icons: ['https://walletconnect.com/walletconnect-logo.png'],
},
};
-
-export const SERIALIZATION_HELPER_SCHEMA_PERMIT_MESSAGE =
- 'FAAFAAAAEAAAAGNvbnRyYWN0X2FkZHJlc3MMBQAAAG5vbmNlBQkAAAB0aW1lc3RhbXANCwAAAGVudHJ5X3BvaW50FgEHAAAAcGF5bG9hZBABAg==';
diff --git a/compliant-reward-distribution/frontend/src/utils.ts b/compliant-reward-distribution/frontend/src/utils.ts
index 95c540f8..0d14331d 100644
--- a/compliant-reward-distribution/frontend/src/utils.ts
+++ b/compliant-reward-distribution/frontend/src/utils.ts
@@ -7,6 +7,8 @@ import {
} from '@concordium/web-sdk';
import { BACKEDN_BASE_URL } from './constants';
+import { WalletProvider } from '../wallet-connection';
+
interface AccountData {
// The account address that was indexed.
accountAddress: AccountAddress.Type;
@@ -207,6 +209,27 @@ export async function getAccountData(
return body;
}
+/**
+ * Request signature from wallet.
+ */
+export async function requestSignature(
+ recentBlockHash: Uint8Array,
+ schema: string,
+ message: string | string[] | object,
+ signer: string,
+ provider: WalletProvider | undefined,
+): Promise {
+ if (!provider) {
+ throw Error(`'provider' is undefined. Connect your wallet.`);
+ }
+
+ const signatures = await provider.signMessage(signer, message, recentBlockHash, schema);
+ if (Object.keys(signatures).length !== 1 || Object.keys(signatures[0]).length !== 1) {
+ throw Error(`Dapp only supports single singer accounts`);
+ }
+ return signatures[0][0];
+}
+
/**
* Fetch the statement to prove from the backend
*/
diff --git a/compliant-reward-distribution/frontend/wallet-connection.tsx b/compliant-reward-distribution/frontend/wallet-connection.tsx
index c737191c..b0fa3e6a 100644
--- a/compliant-reward-distribution/frontend/wallet-connection.tsx
+++ b/compliant-reward-distribution/frontend/wallet-connection.tsx
@@ -3,6 +3,8 @@ import {
AccountTransactionSignature,
CredentialStatements,
HexString,
+ serializeTypeValue,
+ toBuffer,
VerifiablePresentation,
} from '@concordium/web-sdk';
import { SessionTypes } from '@walletconnect/types';
@@ -10,8 +12,15 @@ import SignClient from '@walletconnect/sign-client';
import QRCodeModal from '@walletconnect/qrcode-modal';
import EventEmitter from 'events';
import JSONBigInt from 'json-bigint';
+import { Buffer } from 'buffer';
-import { CHAIN_ID, ID_METHOD, WALLET_CONNECT_SESSION_NAMESPACE, walletConnectOpts } from './src/constants';
+import {
+ CHAIN_ID,
+ CONTEXT_STRING,
+ ID_METHOD,
+ WALLET_CONNECT_SESSION_NAMESPACE,
+ walletConnectOpts,
+} from './src/constants';
export abstract class WalletProvider extends EventEmitter {
abstract connect(): Promise;
@@ -23,7 +32,12 @@ export abstract class WalletProvider extends EventEmitter {
disconnect?(): Promise;
- abstract signMessage(accountAddress: string, message: string): Promise;
+ abstract signMessage(
+ accountAddress: string,
+ message: string | string[] | object,
+ recentBlockHash: Uint8Array,
+ schema: string,
+ ): Promise;
/**
* @param account string when account is changed, undefined when disconnected
@@ -66,8 +80,25 @@ export class BrowserWalletProvider extends WalletProvider {
return browserWalletInstance;
}
- async signMessage(accountAddress: string, message: string): Promise {
- return this.provider.signMessage(accountAddress, message);
+ async signMessage(
+ accountAddress: string,
+ message: string | string[] | object,
+ recentBlockHash: Uint8Array,
+ schema: string,
+ ): Promise {
+ const payload = Buffer.from(
+ serializeTypeValue(
+ { block_hash: Buffer.from(recentBlockHash).toString('hex'), context_string: CONTEXT_STRING, message },
+ toBuffer(schema, 'base64'),
+ ).buffer,
+ ).toString('hex');
+
+ const messageToSign = {
+ data: payload,
+ schema,
+ };
+
+ return this.provider.signMessage(accountAddress, messageToSign);
}
async connect(): Promise {
@@ -155,9 +186,16 @@ export class WalletConnectProvider extends WalletProvider {
}
}
- async signMessage(accountAddress: string, message: string): Promise {
+ async signMessage(
+ accountAddress: string,
+ message: string | string[] | object,
+ recentBlockHash: Uint8Array,
+ schema: string,
+ ): Promise {
console.log(accountAddress);
console.log(message);
+ console.log(recentBlockHash);
+ console.log(schema);
throw new Error('Not yet implemented');
}
diff --git a/compliant-reward-distribution/indexer-and-server/Cargo.toml b/compliant-reward-distribution/indexer-and-server/Cargo.toml
index fc7332b7..3f651a81 100644
--- a/compliant-reward-distribution/indexer-and-server/Cargo.toml
+++ b/compliant-reward-distribution/indexer-and-server/Cargo.toml
@@ -17,7 +17,7 @@ tower-http = { version = "0.4", features = [
"limit",
"fs",
"compression-br",
- "compression-zstd",
+ "compression-zstd"
] }
http = "0.2"
tonic = { version = "0.10", features = ["tls-roots", "tls"] }
diff --git a/compliant-reward-distribution/indexer-and-server/src/bin/server.rs b/compliant-reward-distribution/indexer-and-server/src/bin/server.rs
index 4f6ee95b..537ab1fd 100644
--- a/compliant-reward-distribution/indexer-and-server/src/bin/server.rs
+++ b/compliant-reward-distribution/indexer-and-server/src/bin/server.rs
@@ -7,6 +7,7 @@ use axum::{
};
use chrono::Utc;
use clap::Parser;
+use concordium_rust_sdk::smart_contracts::common::to_bytes;
use concordium_rust_sdk::{
id::{
constants::ArCurve,
@@ -23,17 +24,17 @@ use concordium_rust_sdk::{
};
use indexer::{
constants::{
- CONTEXT_STRING, CURRENT_TWEET_VERIFICATION_VERSION, CURRENT_ZK_PROOF_VERIFICATION_VERSION,
- MAX_REQUEST_LIMIT, SIGNATURE_AND_PROOF_EXPIRY_DURATION_BLOCKS, TESTNET_GENESIS_BLOCK_HASH,
- ZK_STATEMENTS,
+ CONTEXT_STRING, CONTEXT_STRING_2, CURRENT_TWEET_VERIFICATION_VERSION,
+ CURRENT_ZK_PROOF_VERIFICATION_VERSION, MAX_REQUEST_LIMIT,
+ SIGNATURE_AND_PROOF_EXPIRY_DURATION_BLOCKS, TESTNET_GENESIS_BLOCK_HASH, ZK_STATEMENTS,
},
db::{AccountData, Database, StoredAccountData},
error::ServerError,
types::{
CanClaimParam, CanClaimReturn, ClaimExpiryDurationDays, GetAccountDataParam,
- GetPendingApprovalsParam, HasSigningData, Health, PostTweetParam, PostZKProofParam,
- SetClaimedParam, SigningData, UserData, VecAccountDataReturn, ZKProofExtractedData,
- ZKProofStatementsReturn,
+ GetPendingApprovalsParam, HasSigningData, Health, MessageSigned, PostTweetParam,
+ PostZKProofParam, SetClaimedParam, SigningData, UserData, VecAccountDataReturn,
+ ZKProofExtractedData, ZKProofStatementsReturn,
},
};
use sha2::Digest;
@@ -440,25 +441,17 @@ where
.map_err(ServerError::QueryError)?
.block_hash;
- // Calculate the `message_hash` that was signed.
- // The `message_hash` consists of the`block_hash` (this
+ // Calculate the `message` that was signed.
+ // The `message` consists of the`block_hash` (this
// ensures that the signature is generated on the spot and the signature
// expires after SIGNATURE_AND_PROOF_EXPIRY_DURATION_BLOCKS), a context
// string (this ensures that an account can be re-used for signing in different
// Concordium services), and the message.
- let message_bytes = bincode::serialize(message)?;
- let message_hash = sha2::Sha256::digest(
- [
- &block_hash as &[u8],
- &CONTEXT_STRING,
- // Remove the lenght prefix (first 8 bytes).
- &message_bytes[8..],
- ]
- .concat(),
- );
-
- // The Concordium wallets convert the message string into ASCII characters before singing.
- let ascii_characters: Vec = hex::encode(message_hash).as_bytes().to_vec();
+ let message_signed_in_wallet = MessageSigned {
+ block_hash: hex::encode(block_hash),
+ context_string: CONTEXT_STRING_2.to_string(),
+ message,
+ };
// The message signed in the Concordium wallet is prepended with the
// `account` address (signer) and 8 zero bytes. Accounts in the Concordium
@@ -469,8 +462,14 @@ where
// does not accidentally sign a transaction. The account nonce is of type
// u64 (8 bytes).
// Add the prepend to the message and calculate the final message hash.
- let final_message_hash =
- sha2::Sha256::digest([&signer.as_ref() as &[u8], &[0u8; 8], &ascii_characters].concat());
+ let final_message_hash = sha2::Sha256::digest(
+ [
+ &signer.as_ref() as &[u8],
+ &[0u8; 8],
+ to_bytes(&message_signed_in_wallet).as_slice(),
+ ]
+ .concat(),
+ );
// Get the public key of the signer.
diff --git a/compliant-reward-distribution/indexer-and-server/src/constants.rs b/compliant-reward-distribution/indexer-and-server/src/constants.rs
index e28f46ca..f4e2c5aa 100644
--- a/compliant-reward-distribution/indexer-and-server/src/constants.rs
+++ b/compliant-reward-distribution/indexer-and-server/src/constants.rs
@@ -16,6 +16,7 @@ pub const CONTEXT_STRING: [u8; 45] = [
67, 79, 78, 67, 79, 82, 68, 73, 85, 77, 95, 67, 79, 77, 80, 76, 73, 65, 78, 84, 95, 82, 69, 87,
65, 82, 68, 95, 68, 73, 83, 84, 82, 73, 66, 85, 84, 73, 79, 78, 95, 68, 65, 80, 80,
];
+pub const CONTEXT_STRING_2: &str = "CONCORDIUM_COMPLIANT_REWARD_DISTRIBUTION_DAPP";
/// The number of blocks after that a generated signature or ZK proof is
/// considered expired.
diff --git a/compliant-reward-distribution/indexer-and-server/src/types.rs b/compliant-reward-distribution/indexer-and-server/src/types.rs
index 07dd2f2c..9d81bf00 100644
--- a/compliant-reward-distribution/indexer-and-server/src/types.rs
+++ b/compliant-reward-distribution/indexer-and-server/src/types.rs
@@ -3,6 +3,7 @@ use crate::{
DatabasePool,
};
use chrono::Days;
+use concordium_rust_sdk::smart_contracts::common as concordium_std;
use concordium_rust_sdk::{
common::types::Signature,
id::{
@@ -10,6 +11,7 @@ use concordium_rust_sdk::{
id_proof_types::Statement,
types::{AccountAddress, GlobalContext},
},
+ smart_contracts::common::Serial,
types::AbsoluteBlockHeight,
v2::Client,
web3id::{did::Network, Presentation, Web3IdAttribute},
@@ -44,7 +46,7 @@ pub struct Server {
/// additional data to be part of the message signed.
#[derive(serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
-pub struct SigningData {
+pub struct SigningData {
/// Signer account.
pub signer: AccountAddress,
/// Message signed.
@@ -60,7 +62,7 @@ pub struct SigningData {
/// Trait definition of `HasSigningData`. This trait is implemented for all
/// input parameter structs used by endpoints that require a signature check.
pub trait HasSigningData {
- type Message;
+ type Message: Serial;
fn signing_data(&self) -> &SigningData;
}
@@ -88,7 +90,7 @@ pub struct ZKProofExtractedData {
/// Message struct for the `postTweet` endpoint.
#[repr(transparent)]
-#[derive(serde::Deserialize, serde::Serialize)]
+#[derive(serde::Deserialize, serde::Serialize, Serial)]
#[serde(rename_all = "camelCase")]
pub struct TweetMessage {
pub tweet: String,
@@ -113,7 +115,7 @@ pub struct PostTweetParam {
/// Message struct for the `setClaimed` endpoint.
#[repr(transparent)]
-#[derive(serde::Deserialize, serde::Serialize)]
+#[derive(serde::Deserialize, serde::Serialize, Serial)]
#[serde(rename_all = "camelCase")]
pub struct SetClaimedMessage {
/// Vector of accounts that should be marked as `claimed` in the database.
@@ -171,7 +173,7 @@ impl HasSigningData for GetAccountDataParam {
/// Message struct for the `getAccountData` endpoint.
#[repr(transparent)]
-#[derive(serde::Deserialize, serde::Serialize)]
+#[derive(serde::Deserialize, serde::Serialize, Serial)]
#[serde(rename_all = "camelCase")]
pub struct GetAccountDataMessage {
/// Account address for which the data should be retrieved.
@@ -194,7 +196,7 @@ pub struct AccountDataReturn {
}
/// Message struct for the `getPendingApprovals` endpoint.
-#[derive(serde::Deserialize, serde::Serialize)]
+#[derive(serde::Deserialize, serde::Serialize, Serial)]
#[serde(rename_all = "camelCase")]
pub struct GetPendingApprovalsMessage {
/// Limit used in the query to the database.
@@ -272,3 +274,13 @@ impl std::fmt::Display for ClaimExpiryDurationDays {
write!(f, "{:?}", self.0)
}
}
+
+/// Final message signed in the wallet.
+/// It contains in addition the `context_string` (so that signatures cannot be replayed
+/// across Concordium services) and `block_hash` (so that signatures expire).
+#[derive(Debug, Serial)]
+pub struct MessageSigned {
+ pub context_string: String,
+ pub message: T,
+ pub block_hash: String,
+}