컨트랙트 업데이트
다시 한 번 말하지만, 우리는 NEAR 계정이 없는 사람을 포함하여 누구나 십자말풀이 퍼즐에 참여할 수 있기를 바랍니다.
첫 번째로 우승한 사람은 "자신의 자리를 예약"하고 자신이 소유한 계정 또는 만들고 싶은 계정 중 상금을 보낼 곳을 선택합니다.
자리 예약
계획
사용자가 십자말풀이를 처음 방문하면 십자말풀이만 표시됩니다. 로그인 버튼이나 채울 필드(예: memo
필드)가 없습니다.
첫 번째 방문 시, 프론트엔드는 브라우저에 완전히 새로운 무작위 시드 문구를 생성합니다. 이 시드 문구를 사용하여 사용자 고유의 키 쌍을 생성합니다. 임의의 시드 문구가 이미 있는 경우 이 부분을 건너뜁니다. (이전 섹션에서 이에 대한 코드를 다뤘습니다.)
사용자가 가장 먼저 퍼즐을 풀면, 함수 호출(function-call) 액세스 키를 발견하고 해당 키로 submit_solution
을 호출합니다. 이 키는 십자말풀이 계정에 있기 때문에, 기본적으로 다른 사람의 키를 사용하고 있습니다.
사용자가 브라우저에 방금 저장한 임 의의 공개 키를 포함할 수 있도록 submit_solution
에 새 매개변수를 추가할 것입니다.
submit_solution
을 실행하는 동안, 컨트랙트는 Promise를 사용하여 작업을 수행할 수 있으므로, 정답 공개 키를 제거하고 사용자의 공개 키를 추가합니다.
이렇게 하면 십자말풀이 퍼즐을 풀려는 다른 시도가 차단되고 승자가 한 명만 남게 됩니다.
이것은 퍼즐이 세 가지 상태를 가질 수 있음을 의미합니다.
- 풀리지 않음
- 풀렸지만 아직 청구되지 않음(지급되지 않음)
- 청구 및 확정됨
이전 챕터에서 열거형(enum)에 대해 논의했으므로, 이는 단순히 열거형 변형을 수정하는 것입니다.
구현
먼저 submit_solution
가 올바른 정답을 확인하는 방법에 대해 살펴보겠습니다.
Loading...
Instead of hashing the plaintext, we simply check that the public key matches what we know the answer is. (The answer being the series of words representing the solution to the crossword puzzle, used as a seed phrase to create a key pair, including a public key.)
Further down in the submit_solution
method we'll follow our plan by adding a function-call access key (that only the winner has) and removing the access key that was discovered by the winner, so no one else can use it.
Loading...
위의 첫 번째 Promise는 액세스 키를 추가하고 두 번째 Promise는 정답에서 파생된 계정의 액세스 키를 시드 문구로 삭제합니다.
새 함수 호출 액세스 키는 추가할 두 가지 메서드를 호출할 수 있습니다.
claim_reward
— 사용자가 기존 계정을 가지고 있고 경품을 보내고자 하는 경우claim_reward_new_account
— 사용자가 계정이 없는 경우 계정을 생성하고 경품을 보내고자 하는 경우
두 함수 모두 교차 컨트랙트 호출을 수행하고 콜백을 사용하여 결과를 확인합니다. 드디어 이 챕터의 내용에 도달했습니다. 시작하겠습니다!
교차 컨트랙트 호출(Cross-contract call)
특성
우리는 testnet
계정에 배포된 linkdrop 계정에 대해 교차 컨트랙트 호출을 할 것입니다. 우리는 또한 이에 대한 콜백과 (잠재적으로 존재하는) 계정으로의 간단한 전송을 할 것입니다. 또한, 두 메서드를 모두 정의하는 특성을 만들 것입니다.
Loading...
Crossword
구조체 구현에서 callback_after_transfer
와 callback_after_create_account
함수를 구현했을 수 있으므로, 콜백에 대한 특성을 만들 필요가 없습니다. 코드를 좀 더 읽기 쉽게 만들기 위해 특성을 정의하고 구현하기로 했습니다 ::: :::claim_reward
다시 말하지만, 이 함수는 사용자가 십자말풀이를 풀고 기존 계정으로 상금을 보내고자 할 때 호출됩니다.
간단해 보이는데 콜백이 필요한 이유는 무엇인가요? 사용자가 로그인할 때 이전 장에서 콜백을 사용하지 않았습니다. 이를 사용하면 무엇이 제공되나요?
상금을 청구하는 동안 사용자가 실수로 사용자 이름을 잘못 누르거나 고양이가 키보드에서 점프할 가능성이 있습니다. mike.testnet
를 입력하는 대신, mike.testnzzz
를 입력하고 보내기를 누를 수 있습니다. 요약하면, 존재하지 않는 계정으로 상품을 보내려고 하면 그것을 잡아내고자 합니다.
간결함을 위해, Promise 및 콜백에 초점을 맞추고 이 함수의 일부 코드를 건너뛰겠습니다.
pub fn claim_reward(
&mut self,
crossword_pk: PublicKey,
receiver_acc_id: String,
memo: String,
) -> Promise {
let signer_pk = env::signer_account_pk();
...
Promise::new(receiver_acc_id.parse().unwrap())
.transfer(reward_amount)
.then(
Self::ext(env::current_account_id())
.with_static_gas(GAS_FOR_ACCOUNT_CALLBACK)
.callback_after_transfer(
crossword_pk,
receiver_acc_id,
memo,
env::signer_account_pk(),
),
)
}
종종 IDE가 도움이 될 수 있습니다.