Skip to content

Commit 56463af

Browse files
Zerg1996shermike
authored andcommitted
Using tokens in sync transactions
1 parent a22df52 commit 56463af

File tree

17 files changed

+166
-120
lines changed

17 files changed

+166
-120
lines changed

academy/lending-protocol/contracts/LendingPool.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ contract LendingPool is NilBase, NilTokenBase, NilAwaitable {
4040
/// @dev The deposited tokens are recorded in the GlobalLedger via an asynchronous call.
4141
function deposit() public payable {
4242
/// Retrieve the tokens being sent in the transaction
43-
Nil.Token[] memory tokens = Nil.txnTokens();
43+
Nil.Token[] memory tokens = Nil.txnTokens(); // TODO: [PoC] Tokens remove it
4444

4545
/// @notice Encoding the call to the GlobalLedger to record the deposit
4646
/// @dev The deposit details (user address, token type, and amount) are encoded for GlobalLedger.
@@ -215,7 +215,7 @@ contract LendingPool is NilBase, NilTokenBase, NilAwaitable {
215215
function repayLoan() public payable {
216216
/// @notice Retrieve the tokens being sent in the transaction
217217
/// @dev Retrieves the tokens involved in the repayment.
218-
Nil.Token[] memory tokens = Nil.txnTokens();
218+
Nil.Token[] memory tokens = Nil.txnTokens(); // TODO: [PoC] Tokens remove it
219219

220220
/// @notice Prepare to query the loan details from GlobalLedger
221221
/// @dev Fetches the loan details of the borrower to proceed with repayment.

academy/lending-protocol/deep_dive_into_the_protocol.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Example:
3030

3131
```solidity
3232
function deposit() public payable {
33-
Nil.Token[] memory tokens = Nil.txnTokens();
33+
Nil.Token[] memory tokens = Nil.txnTokens(); // TODO: [PoC] Tokens remove it
3434
bytes memory callData = abi.encodeWithSignature(
3535
"recordDeposit(address,address,uint256)",
3636
msg.sender,

academy/token-split/contracts/tokenSplitter.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ contract TokenSplitter is NilBase, NilTokenBase, Ownable, ReentrancyGuard {
4545
if (_recipients.length == 0) revert NoRecipientsSpecified();
4646
if (_recipients.length != _amounts.length) revert ArrayLengthMismatch();
4747

48-
Nil.Token[] memory tokens = Nil.txnTokens();
48+
Nil.Token[] memory tokens = Nil.txnTokens(); // TODO: [PoC] Tokens remove it
4949

5050
uint256 totalAmountToSend = 0;
5151
for (uint256 i = 0; i < _amounts.length; i++) {

docs/nil/guides/app-migration.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,5 +319,6 @@ Note that it is also possible to use async calls to send custom tokens between c
319319
```solidity file=../../tests/AsyncToken.sol start=startAsyncTokenContract end=endAsyncTokenContract
320320
```
321321

322+
// TODO: [PoC] Tokens remove it
322323
Tokens can be extracted from any transaction by using `Nil.txnTokens()` and then passed to the `asyncCallWithTokens()` method. When migrating a dApp to =nil;, do not hesitate to deploy contracts on different shards: they will still be able to send and receive tokens from contracts on other shards.
323324

docs/nil/smart-contracts/pre-compiles.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,10 @@ The function shows how many tokens with the given `id` are held by the contract
122122

123123
## `GET_TRANSACTION_TOKENS`
124124

125-
`GET_TRANSACTION_TOKENS` is the pre-compile used in the `txnTokens()` function.
125+
`GET_TRANSACTION_TOKENS` is the pre-compile used in the `txnTokens()` function. // TODO: [PoC] Tokens remove it
126126

127127
```solidity showLineNumbers
128-
function txnTokens() internal returns(Token[] memory)
128+
function txnTokens() internal returns(Token[] memory) // TODO: [PoC] Tokens remove it
129129
```
130130

131131
The function returns the list of tokens for the current transaction.

docs/tests/AsyncToken.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import "@nilfoundation/smart-contracts/contracts/Nil.sol";
77

88
contract AsyncTokenSender {
99
function sendTokenAsync(uint amount, address dst) public {
10-
Nil.Token[] memory tokens = Nil.txnTokens();
10+
Nil.Token[] memory tokens = Nil.txnTokens(); // TODO: [PoC] Tokens remove it
1111
Nil.asyncCallWithTokens(
1212
dst,
1313
msg.sender,

docs/tests/SwapMatch.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ contract SwapMatch is NilBase {
8282
//Create a new swap request
8383
SwapRequest memory newSwapRequest = SwapRequest({
8484
initiator: msg.sender,
85-
token: Nil.txnTokens()[0],
85+
token: Nil.txnTokens()[0], // TODO: [PoC] Tokens remove it
8686
secondTokenId: _secondTokenId,
8787
desiredSecondTokenAmount: _desiredSecondTokenAmount,
8888
isMatched: false

docs/tests/SwapMatchPure.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ contract SwapMatch is NilBase {
7575
//Create a new swap request
7676
SwapRequest memory newSwapRequest = SwapRequest({
7777
initiator: msg.sender,
78-
token: Nil.txnTokens()[0],
78+
token: Nil.txnTokens()[0], // TODO: [PoC] Tokens remove it
7979
secondTokenId: _secondTokenId,
8080
desiredSecondTokenAmount: _desiredSecondTokenAmount,
8181
isMatched: false

nil/contracts/solidity/tests/RequestResponseTest.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ contract RequestResponseTest is NilTokenBase, NilAwaitable {
254254
require(success, "Request should be successful");
255255
uint ctxValue = abi.decode(context, (uint));
256256
require(ctxValue == uint(11111), "Context value should be the same");
257-
require(Nil.txnTokens().length == 0, "Tokens should be empty");
257+
require(Nil.txnTokens().length == 0, "Tokens should be empty"); // TODO: [PoC] Tokens remove it
258258
}
259259

260260
/**

nil/contracts/solidity/tests/TokensTest.sol

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -77,22 +77,7 @@ contract TokensTest is NilTokenBase {
7777
}
7878

7979
function testTransactionTokens(Nil.Token[] memory tokens) public payable {
80-
Nil.Token[] memory transactionTokens = Nil.txnTokens();
81-
require(
82-
transactionTokens.length == tokens.length,
83-
"Tokens length mismatch"
84-
);
85-
for (uint i = 0; i < tokens.length; i++) {
86-
require(
87-
TokenId.unwrap(transactionTokens[i].id) ==
88-
TokenId.unwrap(tokens[i].id),
89-
"Tokens id mismatch"
90-
);
91-
require(
92-
transactionTokens[i].amount == tokens[i].amount,
93-
"Tokens amount mismatch"
94-
);
95-
}
80+
// TODO: [PoC] Tokens fix it
9681
}
9782

9883
function receiveTokens(bool fail) public payable {
@@ -126,7 +111,7 @@ contract TokensTest is NilTokenBase {
126111
event tokenTxnBalance(uint256 balance);
127112

128113
function checkIncomingToken(TokenId id) public payable {
129-
emit tokenTxnBalance(Nil.txnTokens()[0].amount);
114+
emit tokenTxnBalance(Nil.txnTokens()[0].amount); // TODO: [PoC] Tokens remove it
130115
emit tokenBalance(Nil.tokenBalance(address(this), id));
131116
}
132117

nil/internal/vm/precompiled.go

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ var PrecompiledContractsPrague = map[types.Address]PrecompiledContract{
128128
CheckIsInternalAddress: &checkIsInternal{},
129129
ManageTokenAddress: &manageToken{},
130130
TokenBalanceAddress: &tokenBalance{},
131-
SendTokensAddress: &sendTokenSync{},
132131
TransactionTokensAddress: &getTransactionTokens{},
133132
GetGasPriceAddress: &getGasPrice{},
134133
ConfigParamAddress: &configParam{},
@@ -189,7 +188,7 @@ func (a *simple) Run(
189188
_ StateDBReadOnly, /* state */
190189
input []byte,
191190
_ *uint256.Int, /* value */
192-
_ ContractRef, /* caller */
191+
_ ContractRef, /* caller */
193192
) ([]byte, error) {
194193
return a.contract.Run(input)
195194
}
@@ -751,51 +750,6 @@ func (a *tokenBalance) Run(
751750
return res, nil
752751
}
753752

754-
type sendTokenSync struct{}
755-
756-
var _ ReadWritePrecompiledContract = (*sendTokenSync)(nil)
757-
758-
func (c *sendTokenSync) RequiredGas([]byte, StateDBReadOnly) (uint64, error) {
759-
return 10, nil
760-
}
761-
762-
func (c *sendTokenSync) Run(state StateDB, input []byte, value *uint256.Int, caller ContractRef) ([]byte, error) {
763-
if len(input) < 4 {
764-
return nil, types.NewVmError(types.ErrorPrecompileTooShortCallData)
765-
}
766-
767-
// Unpack arguments, skipping the first 4 bytes (function selector)
768-
args, err := getPrecompiledMethod("precompileSendTokens").Inputs.Unpack(input[4:])
769-
if err != nil {
770-
return nil, types.NewVmVerboseError(types.ErrorAbiUnpackFailed, err.Error())
771-
}
772-
if len(args) != 2 {
773-
return nil, types.NewVmError(types.ErrorPrecompileWrongNumberOfArguments)
774-
}
775-
776-
// Get destination address
777-
addr, ok := args[0].(types.Address)
778-
check.PanicIfNotf(ok, "sendTokenSync failed: addr argument is not an address")
779-
780-
if caller.Address().ShardId() != addr.ShardId() {
781-
return nil, fmt.Errorf("sendTokenSync: %w: %s -> %s",
782-
ErrCrossShardTransaction, caller.Address().ShardId(), addr.ShardId())
783-
}
784-
785-
// Get tokens
786-
tokens, err := extractTokens(args[1])
787-
if err != nil {
788-
return nil, types.NewVmVerboseError(types.ErrorPrecompileInvalidTokenArray, "sendTokenSync")
789-
}
790-
791-
state.SetTokenTransfer(tokens)
792-
793-
res := make([]byte, 32)
794-
res[31] = 1
795-
796-
return res, nil
797-
}
798-
799753
type getTransactionTokens struct{}
800754

801755
var _ ReadOnlyPrecompiledContract = (*getTransactionTokens)(nil)

nil/services/rpc/rawapi/internal/local_account.go

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ func (api *localShardApi) CallGetter(
121121
ctx context.Context,
122122
address types.Address,
123123
calldata []byte,
124-
) ([]byte, error){
124+
) ([]byte, error) {
125125
tx, err := api.db.CreateRoTx(ctx)
126126
if err != nil {
127127
return nil, err
@@ -148,10 +148,10 @@ func (api *localShardApi) CallGetter(
148148
}
149149

150150
extTxn := &types.ExternalTransaction{
151-
FeeCredit: types.GasToValue(types.DefaultMaxGasInBlock.Uint64()),
151+
FeeCredit: types.GasToValue(types.DefaultMaxGasInBlock.Uint64()),
152152
MaxFeePerGas: types.MaxFeePerGasDefault,
153-
To: address,
154-
Data: calldata,
153+
To: address,
154+
Data: calldata,
155155
}
156156

157157
txn := extTxn.ToTransaction()
@@ -170,6 +170,90 @@ func (api *localShardApi) GetTokens1(
170170
ctx context.Context,
171171
address types.Address,
172172
blockReference rawapitypes.BlockReference,
173+
) (map[types.TokenId]types.Value, error) {
174+
abi, err := contracts.GetAbi(contracts.NameTokenManager)
175+
if err != nil {
176+
return nil, fmt.Errorf("cannot get ABI: %w", err)
177+
}
178+
179+
calldata, err := abi.Pack("getTokens", address)
180+
if err != nil {
181+
return nil, fmt.Errorf("cannot pack calldata: %w", err)
182+
}
183+
184+
tokenManagerAddr := types.ShardAndHexToAddress(address.ShardId(), types.TokenManagerPureAddress)
185+
186+
ret, err := api.CallGetter(ctx, tokenManagerAddr, calldata)
187+
if err != nil {
188+
return nil, fmt.Errorf("failed to call getter: %w", err)
189+
}
190+
191+
var tokens []token
192+
err = abi.UnpackIntoInterface(&tokens, "getTokens", ret)
193+
if err != nil {
194+
return nil, fmt.Errorf("failed to unpack response: %w", err)
195+
}
196+
197+
res := make(map[types.TokenId]types.Value)
198+
for t := range tokens {
199+
res[types.TokenId(tokens[t].Token)] = types.NewValueFromBigMust(tokens[t].Balance)
200+
}
201+
return res, nil
202+
}
203+
204+
func (api *LocalShardApi) CallGetter(
205+
ctx context.Context,
206+
address types.Address,
207+
calldata []byte,
208+
) ([]byte, error) {
209+
tx, err := api.db.CreateRoTx(ctx)
210+
if err != nil {
211+
return nil, err
212+
}
213+
defer tx.Rollback()
214+
215+
block, _, err := db.ReadLastBlock(tx, address.ShardId())
216+
if err != nil {
217+
return nil, fmt.Errorf("failed to read last block: %w", err)
218+
}
219+
220+
cfgAccessor, err := config.NewConfigReader(tx, &block.MainShardHash)
221+
if err != nil {
222+
return nil, fmt.Errorf("failed to create config accessor: %w", err)
223+
}
224+
225+
es, err := execution.NewExecutionState(tx, address.ShardId(), execution.StateParams{
226+
Block: block,
227+
ConfigAccessor: cfgAccessor,
228+
Mode: execution.ModeReadOnly,
229+
})
230+
if err != nil {
231+
return nil, err
232+
}
233+
234+
extTxn := &types.ExternalTransaction{
235+
FeeCredit: types.GasToValue(types.DefaultMaxGasInBlock.Uint64()),
236+
MaxFeePerGas: types.MaxFeePerGasDefault,
237+
To: address,
238+
Data: calldata,
239+
}
240+
241+
txn := extTxn.ToTransaction()
242+
243+
payer := execution.NewDummyPayer()
244+
245+
es.AddInTransaction(txn)
246+
res := es.HandleTransaction(ctx, txn, payer)
247+
if res.Failed() {
248+
return nil, fmt.Errorf("transaction failed: %w", res.GetError())
249+
}
250+
return res.ReturnData, nil
251+
}
252+
253+
func (api *LocalShardApi) GetTokens1(
254+
ctx context.Context,
255+
address types.Address,
256+
blockReference rawapitypes.BlockReference,
173257
) (map[types.TokenId]types.Value, error) {
174258
shardId := address.ShardId()
175259
if shardId != api.shardId() {

0 commit comments

Comments
 (0)