diff --git a/contracts/arena-discord-identity/schema/arena-discord-identity.json b/contracts/arena-discord-identity/schema/arena-discord-identity.json index 743be55..b1a7d53 100644 --- a/contracts/arena-discord-identity/schema/arena-discord-identity.json +++ b/contracts/arena-discord-identity/schema/arena-discord-identity.json @@ -55,33 +55,38 @@ "type": "object", "required": [ "addr", - "discord_id", - "username" + "discord_profile" ], "properties": { "addr": { "type": "string" }, - "avatar_hash": { - "type": [ - "string", - "null" - ] - }, + "discord_profile": { + "$ref": "#/definitions/DiscordProfile" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "set_connections" + ], + "properties": { + "set_connections": { + "type": "object", + "required": [ + "connections" + ], + "properties": { "connections": { - "type": [ - "array", - "null" - ], + "type": "array", "items": { "$ref": "#/definitions/DiscordConnection" } - }, - "discord_id": { - "$ref": "#/definitions/Uint64" - }, - "username": { - "type": "string" } }, "additionalProperties": false @@ -222,6 +227,29 @@ }, "additionalProperties": false }, + "DiscordProfile": { + "type": "object", + "required": [ + "user_id", + "username" + ], + "properties": { + "avatar_hash": { + "type": [ + "string", + "null" + ] + }, + "user_id": { + "$ref": "#/definitions/Uint64" + }, + "username": { + "description": "The discord username", + "type": "string" + } + }, + "additionalProperties": false + }, "Expiration": { "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", "oneOf": [ @@ -294,10 +322,10 @@ { "type": "object", "required": [ - "user_id" + "discord_profile" ], "properties": { - "user_id": { + "discord_profile": { "type": "object", "required": [ "addr" @@ -333,6 +361,27 @@ }, "additionalProperties": false }, + { + "type": "object", + "required": [ + "discord_connections" + ], + "properties": { + "discord_connections": { + "type": "object", + "required": [ + "addr" + ], + "properties": { + "addr": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "description": "Query the contract's ownership information", "type": "object", @@ -390,6 +439,52 @@ } } }, + "discord_connections": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Array_of_DiscordConnection", + "type": "array", + "items": { + "$ref": "#/definitions/DiscordConnection" + }, + "definitions": { + "DiscordConnection": { + "type": "object", + "required": [ + "key", + "username" + ], + "properties": { + "key": { + "description": "The type of service connection", + "type": "string" + }, + "username": { + "description": "The service's connection username", + "type": "string" + } + }, + "additionalProperties": false + } + } + }, + "discord_profile": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Nullable_Uint64", + "anyOf": [ + { + "$ref": "#/definitions/Uint64" + }, + { + "type": "null" + } + ], + "definitions": { + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } + }, "ownership": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "Ownership_for_String", @@ -484,24 +579,6 @@ "type": "string" } } - }, - "user_id": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Nullable_Uint64", - "anyOf": [ - { - "$ref": "#/definitions/Uint64" - }, - { - "type": "null" - } - ], - "definitions": { - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } } } } diff --git a/contracts/arena-discord-identity/src/contract.rs b/contracts/arena-discord-identity/src/contract.rs index 7fa220e..9d95eb8 100644 --- a/contracts/arena-discord-identity/src/contract.rs +++ b/contracts/arena-discord-identity/src/contract.rs @@ -6,8 +6,8 @@ use cw2::{ensure_from_older_version, set_contract_version}; use cw_ownable::assert_owner; use crate::{ - msg::{DiscordProfile, ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}, - state::{discord_identity, FAUCET_AMOUNT}, + msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}, + state::{discord_identity, DISCORD_CONNECTIONS, FAUCET_AMOUNT}, ContractError, }; @@ -44,17 +44,21 @@ pub fn execute( info: MessageInfo, msg: ExecuteMsg, ) -> Result { - if info.sender != env.contract.address { + if !matches!(msg, ExecuteMsg::SetConnections { .. }) && info.sender != env.contract.address { assert_owner(deps.storage, &info.sender)?; } match msg { + ExecuteMsg::SetConnections { connections } => { + let discord_profile = discord_identity().load(deps.storage, &info.sender)?; + + DISCORD_CONNECTIONS.save(deps.storage, discord_profile.user_id.u64(), &connections)?; + + Ok(Response::new().add_attribute("action", "set_connections")) + } ExecuteMsg::SetProfile { addr, - discord_id, - username, - avatar_hash, - connections, + discord_profile, } => { let discord_identity = discord_identity(); let user = deps.api.addr_validate(&addr)?; @@ -63,7 +67,7 @@ pub fn execute( && discord_identity .idx .discord_id - .prefix(discord_id.u64()) + .prefix(discord_profile.user_id.u64()) .range(deps.storage, None, None, Order::Descending) .collect::>>()? .is_empty() @@ -84,22 +88,13 @@ pub fn execute( } } - discord_identity.save( - deps.storage, - &user, - &DiscordProfile { - user_id: discord_id, - username, - avatar_hash, - connections, - }, - )?; + discord_identity.save(deps.storage, &user, &discord_profile)?; Ok(Response::new() .add_messages(msgs) .add_attribute("action", "set_profile") .add_attribute("address", user) - .add_attribute("discord_id", discord_id.to_string())) + .add_attribute("discord_id", discord_profile.user_id.to_string())) } ExecuteMsg::SetFaucetAmount { amount } => { FAUCET_AMOUNT.save(deps.storage, &amount)?; @@ -130,7 +125,7 @@ pub fn execute( #[cfg_attr(not(feature = "library"), entry_point)] pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { match msg { - QueryMsg::UserId { addr } => { + QueryMsg::DiscordProfile { addr } => { let addr = deps.api.addr_validate(&addr)?; to_json_binary(&discord_identity().may_load(deps.storage, &addr)?) @@ -143,6 +138,15 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { .keys(deps.storage, None, None, Order::Descending) .collect::>>()?, ), + QueryMsg::DiscordConnections { addr } => { + let addr = deps.api.addr_validate(&addr)?; + let discord_id = discord_identity().load(deps.storage, &addr)?.user_id; + to_json_binary( + &DISCORD_CONNECTIONS + .may_load(deps.storage, discord_id.u64())? + .unwrap_or_default(), + ) + } QueryMsg::Ownership {} => to_json_binary(&cw_ownable::get_ownership(deps.storage)?), } } diff --git a/contracts/arena-discord-identity/src/msg.rs b/contracts/arena-discord-identity/src/msg.rs index 773eaf1..3533bd6 100644 --- a/contracts/arena-discord-identity/src/msg.rs +++ b/contracts/arena-discord-identity/src/msg.rs @@ -13,10 +13,10 @@ pub struct InstantiateMsg { pub enum ExecuteMsg { SetProfile { addr: String, - discord_id: Uint64, - username: String, - avatar_hash: Option, - connections: Option>, + discord_profile: DiscordProfile, + }, + SetConnections { + connections: Vec, }, SetFaucetAmount { amount: Coin, @@ -29,9 +29,11 @@ pub enum ExecuteMsg { #[derive(QueryResponses, cw_orch::QueryFns)] pub enum QueryMsg { #[returns(Option)] - UserId { addr: String }, + DiscordProfile { addr: String }, #[returns(Vec)] ConnectedWallets { discord_id: Uint64 }, + #[returns(Vec)] + DiscordConnections { addr: String }, } #[cw_serde] @@ -45,7 +47,6 @@ pub struct DiscordProfile { /// The discord username pub username: String, pub avatar_hash: Option, - pub connections: Option>, } #[cw_serde] diff --git a/contracts/arena-discord-identity/src/state.rs b/contracts/arena-discord-identity/src/state.rs index 33b27e2..22db5d1 100644 --- a/contracts/arena-discord-identity/src/state.rs +++ b/contracts/arena-discord-identity/src/state.rs @@ -1,7 +1,7 @@ use cosmwasm_std::{Addr, Coin}; -use cw_storage_plus::{Index, IndexList, IndexedMap, Item, MultiIndex}; +use cw_storage_plus::{Index, IndexList, IndexedMap, Item, Map, MultiIndex}; -use crate::msg::DiscordProfile; +use crate::msg::{DiscordConnection, DiscordProfile}; pub struct DiscordProfileIndexes<'a> { pub discord_id: MultiIndex<'a, u64, DiscordProfile, &'a Addr>, @@ -26,4 +26,5 @@ pub fn discord_identity<'a>() -> IndexedMap<'a, &'a Addr, DiscordProfile, Discor IndexedMap::new("discord_identity", indexes) } +pub const DISCORD_CONNECTIONS: Map> = Map::new("discord_connections"); pub const FAUCET_AMOUNT: Item = Item::new("faucet_amount"); diff --git a/scripts/state.json b/scripts/state.json index 9ff27bd..a47096f 100644 --- a/scripts/state.json +++ b/scripts/state.json @@ -4,7 +4,7 @@ "code_ids": { "arena_competition_enrollment": 2654, "arena_core": 2217, - "arena_discord_identity": 2759, + "arena_discord_identity": 2819, "arena_escrow": 2216, "arena_group": 2224, "arena_league_module": 2219,