스케일드 UI 금액 통합 가이드
Solana에서 스케일드 UI 금액 확장 기능 지원하기
배경
스케일드 UI 금액 확장 기능을 통해 토큰 발행자는 사용자의 토큰 잔액의 UI 금액을 계산할 때 사용할 승수를 지정할 수 있습니다. 이를 통해 발행자는 리베이싱 토큰을 생성하고 주식 분할과 같은 기능을 활성화할 수 있습니다. 이 확장 기능은 이자 발생 토큰 확장 기능과 마찬가지로 순전히 시각적인 UI 금액을 제공하므로 팀은 좋은 사용자 경험을 제공하기 위해 추가 작업을 수행해야 합니다. 기본 계산 및 전송은 모두 프로그램에서 원시 금액을 사용하여 이루어집니다.
리소스:
요약
- 최종 사용자는 가능한 한 토큰 가격, 토큰 잔액 및 토큰 금액에 대해 UIAmount(원시 금액 * 승수)와 상호 작용해야 합니다
- dApp 및 서비스 제공업체는 모든 계산에 원시 금액과 스케일링되지 않은 가격을 사용하고 최종 단계에서 사용자를 위해 변환해야 합니다
- 더 쉬운 통합을 위해 스케일링된 금액과 스케일링되지 않은 금액 모두에 대한 과거 가격 피드를 제공해야 합니다
- 정확한 과거 데이터를 위해 과거 승수 값에 접근할 수 있어야 합니다
용어 정의
- 승수: UI 금액 계산에 사용되는 정적이지만 업데이트 가능한 승수
- UIAmount: 승수 * 원시 금액 (일명: 스케일링된 금액)
- 원시 금액: 금액 (일명: 스케일링되지 않은 금액)
현재 잔액
표시용 현재 금액
- 스케일드 UI 금액 확장 기능을 사용하는 토큰의 금액을 최종 사용자에게 표시할
때는 다음 중 하나를 사용해야 합니다:
- UIAmount/UIAmountString (권장)
- 원시 금액 * 승수의 수동 계산
- 토큰이 가진 소수점 자릿수에 따라 이 값을 잘라내는 것을 권장합니다.
- 예: yUSD가 6자리 소수점을 가지고 있고 사용자의 UIAmount가 1.123456789인 경우 "1.123456"으로 표시해야 합니다
이 데이터를 얻을 수 있는 곳:
- 사용자의 실시간 잔액에 대해 위 금액의 업데이트된 정보를 얻으려면 getTokenAccountBalance 또는 getAccountInfo를 호출하세요
- 임의 금액에 대한 UI 금액을 알아야 하는 경우
amountToUiAmountForMintWithoutSimulation
(web3.js v1) 함수를 호출하거나 amountToUiAmount를 사용하여 트랜잭션을 시뮬레이션하여 계산할 수 있습니다.- 참고: amountToUiAmount는 트랜잭션 시뮬레이션이 필요하며 이는 잔액이 있는 유효한 수수료 지불자도 필요함을 의미합니다. 이러한 이유로 이 방법은 잔액을 확인하는 기본 방법이 되어서는 안 됩니다.
RPC 호출
getTokenAccountBalance
- token account 잔액과 mint 정보를 반환합니다
import { address, createSolanaRpc } from "@solana/kit";const rpc_url = "https://api.devnet.solana.com";const rpc = createSolanaRpc(rpc_url);let tokenAddress = address("2uuvxpnEKw52aTqNerHiQ3WeSqZriCMNVt8LhWfrkbPk");let tokenBalance = await rpc.getTokenAccountBalance(tokenAddress).send();console.log("Token Balance:", tokenBalance);/* Token Balance: {context: { apiVersion: '2.2.14', slot: 381132711n },value: {amount: '10000000',decimals: 6,uiAmount: 20,uiAmountString: '20'}} */
getAccountInfo
- 계정 정보와 mint 정보를 반환합니다
import { address, createSolanaRpc } from "@solana/kit";const rpc_url = "https://api.devnet.solana.com";const rpc = createSolanaRpc(rpc_url);const publicKey = address("2uuvxpnEKw52aTqNerHiQ3WeSqZriCMNVt8LhWfrkbPk");const accountInfo = await rpc.getAccountInfo(publicKey).send();console.log("Account Info:",JSON.stringify(accountInfo,(key, value) => (typeof value === "bigint" ? value.toString() : value),2));/* Account Info: {"context": {"apiVersion": "2.2.14","slot": "381133640"},"value": {"data": {"parsed": {"info": {"extensions": [{"extension": "immutableOwner"},{"extension": "pausableAccount"}],"isNative": false,"mint": "BZCd6HfTbb5ZYJ8hQsm8282tG4QzLyeqFR6tdgQA9EAG","owner": "G7ARQSUCwNrfvTDUCZvM5xdiRdBJiN3qVw2PryD8Wnib","state": "initialized","tokenAmount": {"amount": "10000000","decimals": 6,"uiAmount": 20,"uiAmountString": "20"}},"type": "account"},"program": "spl-token-2022","space": "174"},"executable": false,"lamports": "2101920","owner": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb","rentEpoch": "18446744073709551615","space": "174"}} */
현재 금액 업데이트하기
발행자가 언제든지 승수를 업데이트할 수 있기 때문에 계정 잔액을 최신 상태로 유지하기 위해 주기적으로 폴링하는 것을 고려할 수 있습니다. 발행자는 하루에 한 번 이상 이 승수를 업데이트할 가능성이 낮습니다. 승수가 미래 날짜로 설정된 경우, 이 업데이트 시간에 자동으로 폴링할 수 있습니다
트랜잭션에서의 토큰 금액 (전송 / 스왑 등)
- 사용자는 조정된 "UIAmount"로 해석될 금액을 입력해야 합니다. 이를 처리하는 앱은
트랜잭션을 위해 원시 토큰 금액으로 변환해야 합니다.
- 반올림 문제가 있는 경우, 내림하여 트랜잭션 실패 위험보다는 아주 작은 양의 먼지(dust)를 남기는 것이 좋습니다
- 이 변환을 수행하려면
uiAmountToAmountForMintWithoutSimulation
(web3.js v1) 함수를 사용하거나 amountToUiAmount를 사용하여 트랜잭션을 시뮬레이션할 수 있습니다.
web3js-uiAmountToAmountForMintWithoutSimulation.ts
import { uiAmountToAmountForMintWithoutSimulation } from "@solana/web3.js";import { Connection, PublicKey, clusterApiUrl } from "@solana/web3.js";const connection = new Connection(clusterApiUrl("devnet"), "confirmed");const mint = new PublicKey("BZCd6HfTbb5ZYJ8hQsm8282tG4QzLyeqFR6tdgQA9EAG");const uiAmount = "20.2";const rawAmount = await uiAmountToAmountForMintWithoutSimulation(connection as unknown as Connection,mint,uiAmount);console.log("Raw Amount:", rawAmount);/* Raw Amount: 20200000 */
- 앱은 사용자가 "최대" 또는 "전체" 잔액으로 작업을 요청할 때 총 원시 금액을
사용해야 합니다. 이렇게 하면 잔여 먼지가 남지 않습니다.
- 선택 사항: "최대"가 사용될 때 계정을 자동으로 닫아 사용자에게 저장소 보증금을 환불하는 것을 고려할 수 있습니다.
토큰 가격
- 토큰 가격은 가능한 한 항상 스케일링된 가격으로 표시되어야 합니다.
- 오라클과 같은 가격 피드 서비스 제공업체인 경우, 스케일링된 가격과 스케일링되지
않은 가격을 모두 제공해야 합니다.
- 가능한 한 스케일링된 UI 금액 확장의 복잡성을 추상화하는 SDK/API를 제공하세요.
현재 승수
- 현재 승수는 언제든지
getAccountInfo
를 호출하여 토큰 민트에서 읽을 수 있습니다. 또한 미래 승수가 설정된 경우, 이 정보도 토큰 민트에서 확인할 수 있습니다. UX를 혼란스럽게 할 수 있으므로 이 승수를 표시하지 않는 것이 좋습니다.
import { address, createSolanaRpc } from "@solana/kit";const rpc_url = "https://api.devnet.solana.com";const rpc = createSolanaRpc(rpc_url);const publicKey = address("BZCd6HfTbb5ZYJ8hQsm8282tG4QzLyeqFR6tdgQA9EAG");const accountInfo = await rpc.getAccountInfo(publicKey, { encoding: "jsonParsed" }).send();const mintData = accountInfo.value?.data as Readonly<{parsed: {info?: {extensions: {extension: string;state: object;}[];};type: string;};program: string;space: bigint;}>;const scaledUiAmountConfig = mintData.parsed.info?.extensions?.find((extension) => extension.extension === "scaledUiAmountConfig") as Readonly<{state: {newMultiplierEffectiveTimestamp: number;newMultiplier: number;multiplier: number;};}>;const currentMultiplier =scaledUiAmountConfig?.state &&Date.now() / 1000 >=scaledUiAmountConfig.state.newMultiplierEffectiveTimestamp? scaledUiAmountConfig.state.newMultiplier: scaledUiAmountConfig.state.multiplier;console.log("Scaled UI Amount Config:", scaledUiAmountConfig);console.log("Current Multiplier:", currentMultiplier);/*Scaled UI Amount Config: {extension: 'scaledUiAmountConfig',state: {authority: 'G7ARQSUCwNrfvTDUCZvM5xdiRdBJiN3qVw2PryD8Wnib',multiplier: '2',newMultiplier: '2',newMultiplierEffectiveTimestamp: 1743000000n}}Current Multiplier: 2*/
과거 데이터
가격 피드의 과거 데이터
- 과거 데이터를 제공하는 서비스는 스케일링된 UI 금액 확장에 대해 스케일링된 가격과 스케일링되지 않은 가격을 모두 저장하고 표시해야 합니다.
- 스케일링된 금액이 가장 자주 사용될 것으로 예상됩니다. 이는 전통적인 금융 세계에서 주식 분할이 있는 토큰과 관련된 차트를 처리하는 방식과 일치합니다.
금액에 대한 과거 데이터
- 과거에 전송된 잔액을 표시하려면 해당 slot에서의 승수에 접근해야 합니다. 또한 트랜잭션을 처리할 때 전송에 대한 UiAmount를 저장하여 향후 이 계산을 피할 수 있습니다.
이전 버전과의 호환성
- 기본적으로 스케일된 UI 금액 확장을 이해하지 못하는 지갑과 애플리케이션은 비스케일 가격 × 원시 금액을 곱하여 활동의 총 가격을 올바르게 표시합니다.
- 그러나 비스케일 가격을 표시하여 사용자에게 혼란을 줄 수 있습니다.
- 이를 통해 팀들이 스케일된 UI 금액 확장을 사용하는 토큰과 호환되도록 dapp을 업데이트하도록 장려하며, 이 과정에서 기꺼이 지원을 제공할 것입니다.
플랫폼별 권장 통합 우선순위
일반 요구사항
요구사항 | 설명 | 우선순위 |
---|---|---|
UiAmount를 사용한 사용자 작업 지원 | 모든 사용자 작업은 앱 전체에서 UiAmount가 활성화된 경우 UiAmount로 입력해야 합니다. 앱에서 UiAmount가 표시되지 않는 경우, 앱이 업데이트될 때까지 원시 금액을 사용해야 합니다. | P0 |
지갑
요구사항 | 설명 | 우선순위 |
---|---|---|
스케일된 잔액 표시 | 스케일된 금액(uiAmount)을 주요 잔액으로 표시합니다. | P0 |
토큰 전송 지원 | 최종 사용자는 스케일된 잔액(원시 금액 × 잔액)으로 전송 금액을 입력해야 합니다. | P0 |
현재 가격 표시 | 사용자에게 스케일된 현재 가격을 표시합니다. | P0 |
거래 내역 메타데이터 | 가능한 모든 전송에 대해 스케일된 금액(UIAmount)을 표시합니다. | P1 |
거래 내역에 승수 업데이트 표시 | 승수 업데이트가 발생하면 사용자의 거래 내역에 이벤트로 표시하고 증가된 금액을 포함합니다. | P2 |
가격 내역 그래프 표시 | 가격 그래프에 스케일된 가격을 반영합니다. | P1 |
온보딩/툴팁 | 스케일된 UI 금액 확장을 사용하는 토큰에 대해 사용자를 교육하기 위한 툴팁이나 온보딩을 제공합니다. | P2 |
익스플로러
요구사항 | 설명 | 우선순위 |
---|---|---|
토큰 상세 페이지 개선 | 총 스케일링된 시가총액 및 현재 승수와 같은 메타데이터 표시 | P0 |
잔액에 대한 스케일링된 잔액 표시 | 현재 잔액에 대한 스케일링된 잔액(UiAmount) 표시 | P0 |
거래에 대한 스케일링된 잔액 표시 | 과거 거래의 전송 금액에 대한 스케일링된 잔액(UiAmount) 표시 | P0 |
거래에 대한 스케일링된 가격 표시 | 이전 거래에 대한 스케일링된 가격 표시 | P1 |
승수 업데이트 거래 올바르게 파싱 및 표시 | 승수 업데이트에 대한 세부 정보 올바르게 표시 | P2 |
시장 데이터 애그리게이터(예: 코인게코)
요구사항 | 설명 | 우선순위 |
---|---|---|
스케일링된 데이터를 위한 API 업데이트 | 시간에 따른 승수 변화와 스케일링된 가격 피드를 포함하도록 API 기능 확장 | P0 |
스케일링 조정이 포함된 총 공급량 | 총 공급량 및 총 시가총액 표시 시 스케일링된 잔액 고려 | P0 |
과거 가격 추적 | 시간에 따른 스케일링된 가격을 사용하여 과거 차트 제공 | P1 |
과거 승수 추적 | 이자 발생 토큰에 대한 승수 업데이트의 과거 마커 제공 | P2 |
교육 콘텐츠 또는 설명 | 스케일링된 토큰의 작동 방식을 설명하는 간단한 설명이나 툴팁 포함 | P2 |
가격 피드 제공업체
요구사항 | 설명 | 우선순위 |
---|---|---|
스케일링 및 비스케일링 가격 피드 | 스케일링 및 비스케일링 가격 모두에 대한 가격 피드 제공 | P0 |
과거 승수 데이터 | 과거 승수 변경 사항이 포함된 API 제공 | P0 |
과거 가격 데이터 | 스케일링 및 비스케일링 금액 모두에 기반한 과거 가격이 포함된 API 제공 | P0 |
DEX
요구사항 | 설명 | 우선순위 |
---|---|---|
리베이스된 토큰 잔액 표시 | UI에서 거래 또는 유동성 제공을 위한 조정된 잔액 표시. (백엔드는 여전히 원시 금액 사용 가능) | P0 |
토큰 작업 지원 | 최종 사용자는 UiAmount 잔액(승수 * 원시 금액)으로 작업 금액을 입력해야 함. | P0 |
가격 피드 적응 | 현재 가격을 표시하는 데 가격 피드가 사용되는 모든 곳에서 최종 사용자에게 조정된 가격 제공. | P1 |
가격 기록 그래프 표시 | 가격 그래프에 조정된 가격 반영 | P1 |
Is this page helpful?